VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/tests/additions/tdAddGuestCtrl.py@ 84572

Last change on this file since 84572 was 84572, checked in by vboxsync, 5 years ago

Validation Kit/tdAddGuestCtrl.py: Try converting other data types to a string in limitString().

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 247.1 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# pylint: disable=too-many-lines
4
5"""
6VirtualBox Validation Kit - Guest Control Tests.
7"""
8
9__copyright__ = \
10"""
11Copyright (C) 2010-2020 Oracle Corporation
12
13This file is part of VirtualBox Open Source Edition (OSE), as
14available from http://www.virtualbox.org. This file is free software;
15you can redistribute it and/or modify it under the terms of the GNU
16General Public License (GPL) as published by the Free Software
17Foundation, in version 2 as it comes in the "COPYING" file of the
18VirtualBox OSE distribution. VirtualBox OSE is distributed in the
19hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20
21The contents of this file may alternatively be used under the terms
22of the Common Development and Distribution License Version 1.0
23(CDDL) only, as it comes in the "COPYING.CDDL" file of the
24VirtualBox OSE distribution, in which case the provisions of the
25CDDL are applicable instead of those of the GPL.
26
27You may elect to license modified versions of this file under the
28terms and conditions of either the GPL or the CDDL or both.
29"""
30__version__ = "$Revision: 84572 $"
31
32# Standard Python imports.
33import errno
34import os
35import random
36import struct
37import sys
38import threading
39import time
40
41# Only the main script needs to modify the path.
42try: __file__
43except: __file__ = sys.argv[0];
44g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))));
45sys.path.append(g_ksValidationKitDir);
46
47# Validation Kit imports.
48from testdriver import reporter;
49from testdriver import base;
50from testdriver import testfileset;
51from testdriver import vbox;
52from testdriver import vboxcon;
53from testdriver import vboxtestfileset;
54from testdriver import vboxwrappers;
55from common import utils;
56
57# Python 3 hacks:
58if sys.version_info[0] >= 3:
59 long = int # pylint: disable=redefined-builtin,invalid-name
60 xrange = range; # pylint: disable=redefined-builtin,invalid-name
61
62def limitString(sString, cLimit = 32):
63 """
64 Returns a string with ellipsis ("...") when exceeding the specified limit.
65 Useful for toning down logging. By default strings will be shortened at 32 characters.
66 """
67 if not isinstance(sString, str):
68 sString = str(sString);
69 cLen = len(sString);
70 if not cLen:
71 return '';
72 return (sString[:cLimit] + '...[%d more]' % (cLen - cLimit)) if cLen > cLimit else sString;
73
74class GuestStream(bytearray):
75 """
76 Class for handling a guest process input/output stream.
77
78 @todo write stdout/stderr tests.
79 """
80 def appendStream(self, stream, convertTo = '<b'):
81 """
82 Appends and converts a byte sequence to this object;
83 handy for displaying a guest stream.
84 """
85 self.extend(struct.pack(convertTo, stream));
86
87
88class tdCtxCreds(object):
89 """
90 Provides credentials to pass to the guest.
91 """
92 def __init__(self, sUser = None, sPassword = None, sDomain = None):
93 self.oTestVm = None;
94 self.sUser = sUser;
95 self.sPassword = sPassword;
96 self.sDomain = sDomain;
97
98 def applyDefaultsIfNotSet(self, oTestVm):
99 """
100 Applies credential defaults, based on the test VM (guest OS), if
101 no credentials were set yet.
102 """
103 self.oTestVm = oTestVm;
104 assert self.oTestVm is not None;
105
106 if self.sUser is None:
107 self.sUser = self.oTestVm.getTestUser();
108
109 if self.sPassword is None:
110 self.sPassword = self.oTestVm.getTestUserPassword(self.sUser);
111
112 if self.sDomain is None:
113 self.sDomain = '';
114
115class tdTestGuestCtrlBase(object):
116 """
117 Base class for all guest control tests.
118
119 Note: This test ASSUMES that working Guest Additions
120 were installed and running on the guest to be tested.
121 """
122 def __init__(self, oCreds = None):
123 self.oGuest = None; ##< IGuest.
124 self.oCreds = oCreds ##< type: tdCtxCreds
125 self.timeoutMS = 30 * 1000; ##< 30s timeout
126 self.oGuestSession = None; ##< IGuestSession reference or None.
127
128 def setEnvironment(self, oSession, oTxsSession, oTestVm):
129 """
130 Sets the test environment required for this test.
131 """
132 _ = oTxsSession;
133
134 try:
135 self.oGuest = oSession.o.console.guest;
136 except:
137 reporter.errorXcpt();
138
139 if self.oCreds is None:
140 self.oCreds = tdCtxCreds();
141 self.oCreds.applyDefaultsIfNotSet(oTestVm);
142
143 return True;
144
145 def uploadLogData(self, oTstDrv, aData, sFileName, sDesc):
146 """
147 Uploads (binary) data to a log file for manual (later) inspection.
148 """
149 reporter.log('Creating + uploading log data file "%s"' % sFileName);
150 sHstFileName = os.path.join(oTstDrv.sScratchPath, sFileName);
151 try:
152 oCurTestFile = open(sHstFileName, "wb");
153 oCurTestFile.write(aData);
154 oCurTestFile.close();
155 except:
156 return reporter.error('Unable to create temporary file for "%s"' % (sDesc,));
157 return reporter.addLogFile(sHstFileName, 'misc/other', sDesc);
158
159 def createSession(self, sName, fIsError = True):
160 """
161 Creates (opens) a guest session.
162 Returns (True, IGuestSession) on success or (False, None) on failure.
163 """
164 if self.oGuestSession is None:
165 if sName is None:
166 sName = "<untitled>";
167
168 reporter.log('Creating session "%s" ...' % (sName,));
169 try:
170 self.oGuestSession = self.oGuest.createSession(self.oCreds.sUser,
171 self.oCreds.sPassword,
172 self.oCreds.sDomain,
173 sName);
174 except:
175 # Just log, don't assume an error here (will be done in the main loop then).
176 reporter.maybeErrXcpt(fIsError, 'Creating a guest session "%s" failed; sUser="%s", pw="%s", sDomain="%s":'
177 % (sName, self.oCreds.sUser, self.oCreds.sPassword, self.oCreds.sDomain));
178 return (False, None);
179
180 reporter.log('Waiting for session "%s" to start within %dms...' % (sName, self.timeoutMS));
181 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start, ];
182 try:
183 waitResult = self.oGuestSession.waitForArray(aeWaitFor, self.timeoutMS);
184
185 #
186 # Be nice to Guest Additions < 4.3: They don't support session handling and
187 # therefore return WaitFlagNotSupported.
188 #
189 if waitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
190 # Just log, don't assume an error here (will be done in the main loop then).
191 reporter.maybeErr(fIsError, 'Session did not start successfully, returned wait result: %d' % (waitResult,));
192 return (False, None);
193 reporter.log('Session "%s" successfully started' % (sName,));
194 except:
195 # Just log, don't assume an error here (will be done in the main loop then).
196 reporter.maybeErrXcpt(fIsError, 'Waiting for guest session "%s" (usr=%s;pw=%s;dom=%s) to start failed:'
197 % (sName, self.oCreds.sUser, self.oCreds.sPassword, self.oCreds.sDomain,));
198 return (False, None);
199 else:
200 reporter.log('Warning: Session already set; this is probably not what you want');
201 return (True, self.oGuestSession);
202
203 def setSession(self, oGuestSession):
204 """
205 Sets the current guest session and closes
206 an old one if necessary.
207 """
208 if self.oGuestSession is not None:
209 self.closeSession();
210 self.oGuestSession = oGuestSession;
211 return self.oGuestSession;
212
213 def closeSession(self, fIsError = True):
214 """
215 Closes the guest session.
216 """
217 if self.oGuestSession is not None:
218 try:
219 sName = self.oGuestSession.name;
220 except:
221 return reporter.errorXcpt();
222
223 reporter.log('Closing session "%s" ...' % (sName,));
224 try:
225 self.oGuestSession.close();
226 self.oGuestSession = None;
227 except:
228 # Just log, don't assume an error here (will be done in the main loop then).
229 reporter.maybeErrXcpt(fIsError, 'Closing guest session "%s" failed:' % (sName,));
230 return False;
231 return True;
232
233class tdTestCopyFrom(tdTestGuestCtrlBase):
234 """
235 Test for copying files from the guest to the host.
236 """
237 def __init__(self, sSrc = "", sDst = "", oCreds = None, afFlags = None, oSrc = None):
238 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
239 self.sSrc = sSrc;
240 self.sDst = sDst;
241 self.afFlags = afFlags;
242 self.oSrc = oSrc # type: testfileset.TestFsObj
243 if oSrc and not sSrc:
244 self.sSrc = oSrc.sPath;
245
246class tdTestCopyFromDir(tdTestCopyFrom):
247
248 def __init__(self, sSrc = "", sDst = "", oCreds = None, afFlags = None, oSrc = None, fIntoDst = False):
249 tdTestCopyFrom.__init__(self, sSrc, sDst, oCreds, afFlags, oSrc);
250 self.fIntoDst = fIntoDst; # hint to the verification code that sDst == oSrc, rather than sDst+oSrc.sNAme == oSrc.
251
252class tdTestCopyFromFile(tdTestCopyFrom):
253 pass;
254
255class tdTestRemoveHostDir(object):
256 """
257 Test step that removes a host directory tree.
258 """
259 def __init__(self, sDir):
260 self.sDir = sDir;
261
262 def execute(self, oTstDrv, oVmSession, oTxsSession, oTestVm, sMsgPrefix):
263 _ = oTstDrv; _ = oVmSession; _ = oTxsSession; _ = oTestVm; _ = sMsgPrefix;
264 if os.path.exists(self.sDir):
265 if base.wipeDirectory(self.sDir) != 0:
266 return False;
267 try:
268 os.rmdir(self.sDir);
269 except:
270 return reporter.errorXcpt('%s: sDir=%s' % (sMsgPrefix, self.sDir,));
271 return True;
272
273
274
275class tdTestCopyTo(tdTestGuestCtrlBase):
276 """
277 Test for copying files from the host to the guest.
278 """
279 def __init__(self, sSrc = "", sDst = "", oCreds = None, afFlags = None):
280 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
281 self.sSrc = sSrc;
282 self.sDst = sDst;
283 self.afFlags = afFlags;
284
285class tdTestCopyToFile(tdTestCopyTo):
286 pass;
287
288class tdTestCopyToDir(tdTestCopyTo):
289 pass;
290
291class tdTestDirCreate(tdTestGuestCtrlBase):
292 """
293 Test for directoryCreate call.
294 """
295 def __init__(self, sDirectory = "", oCreds = None, fMode = 0, afFlags = None):
296 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
297 self.sDirectory = sDirectory;
298 self.fMode = fMode;
299 self.afFlags = afFlags;
300
301class tdTestDirCreateTemp(tdTestGuestCtrlBase):
302 """
303 Test for the directoryCreateTemp call.
304 """
305 def __init__(self, sDirectory = "", sTemplate = "", oCreds = None, fMode = 0, fSecure = False):
306 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
307 self.sDirectory = sDirectory;
308 self.sTemplate = sTemplate;
309 self.fMode = fMode;
310 self.fSecure = fSecure;
311
312class tdTestDirOpen(tdTestGuestCtrlBase):
313 """
314 Test for the directoryOpen call.
315 """
316 def __init__(self, sDirectory = "", oCreds = None, sFilter = "", afFlags = None):
317 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
318 self.sDirectory = sDirectory;
319 self.sFilter = sFilter;
320 self.afFlags = afFlags or [];
321
322class tdTestDirRead(tdTestDirOpen):
323 """
324 Test for the opening, reading and closing a certain directory.
325 """
326 def __init__(self, sDirectory = "", oCreds = None, sFilter = "", afFlags = None):
327 tdTestDirOpen.__init__(self, sDirectory, oCreds, sFilter, afFlags);
328
329class tdTestExec(tdTestGuestCtrlBase):
330 """
331 Specifies exactly one guest control execution test.
332 Has a default timeout of 5 minutes (for safety).
333 """
334 def __init__(self, sCmd = "", asArgs = None, aEnv = None, afFlags = None, # pylint: disable=too-many-arguments
335 timeoutMS = 5 * 60 * 1000, oCreds = None, fWaitForExit = True):
336 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
337 self.sCmd = sCmd;
338 self.asArgs = asArgs if asArgs is not None else [sCmd,];
339 self.aEnv = aEnv;
340 self.afFlags = afFlags or [];
341 self.timeoutMS = timeoutMS;
342 self.fWaitForExit = fWaitForExit;
343 self.uExitStatus = 0;
344 self.iExitCode = 0;
345 self.cbStdOut = 0;
346 self.cbStdErr = 0;
347 self.sBuf = '';
348
349class tdTestFileExists(tdTestGuestCtrlBase):
350 """
351 Test for the file exists API call (fileExists).
352 """
353 def __init__(self, sFile = "", oCreds = None):
354 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
355 self.sFile = sFile;
356
357class tdTestFileRemove(tdTestGuestCtrlBase):
358 """
359 Test querying guest file information.
360 """
361 def __init__(self, sFile = "", oCreds = None):
362 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
363 self.sFile = sFile;
364
365class tdTestRemoveBase(tdTestGuestCtrlBase):
366 """
367 Removal base.
368 """
369 def __init__(self, sPath, fRcExpect = True, oCreds = None):
370 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
371 self.sPath = sPath;
372 self.fRcExpect = fRcExpect;
373
374 def execute(self, oSubTstDrv):
375 """
376 Executes the test, returns True/False.
377 """
378 _ = oSubTstDrv;
379 return True;
380
381 def checkRemoved(self, sType):
382 """ Check that the object was removed using fObjExists. """
383 try:
384 fExists = self.oGuestSession.fsObjExists(self.sPath, False);
385 except:
386 return reporter.errorXcpt('fsObjExists failed on "%s" after deletion (type: %s)' % (self.sPath, sType));
387 if fExists:
388 return reporter.error('fsObjExists says "%s" still exists after deletion (type: %s)!' % (self.sPath, sType));
389 return True;
390
391class tdTestRemoveFile(tdTestRemoveBase):
392 """
393 Remove a single file.
394 """
395 def __init__(self, sPath, fRcExpect = True, oCreds = None):
396 tdTestRemoveBase.__init__(self, sPath, fRcExpect, oCreds);
397
398 def execute(self, oSubTstDrv):
399 reporter.log2('Deleting file "%s" ...' % (limitString(self.sPath),));
400 try:
401 if oSubTstDrv.oTstDrv.fpApiVer >= 5.0:
402 self.oGuestSession.fsObjRemove(self.sPath);
403 else:
404 self.oGuestSession.fileRemove(self.sPath);
405 except:
406 reporter.maybeErrXcpt(self.fRcExpect, 'Removing "%s" failed' % (self.sPath,));
407 return not self.fRcExpect;
408 if not self.fRcExpect:
409 return reporter.error('Expected removing "%s" to failed, but it succeeded' % (self.sPath,));
410
411 return self.checkRemoved('file');
412
413class tdTestRemoveDir(tdTestRemoveBase):
414 """
415 Remove a single directory if empty.
416 """
417 def __init__(self, sPath, fRcExpect = True, oCreds = None):
418 tdTestRemoveBase.__init__(self, sPath, fRcExpect, oCreds);
419
420 def execute(self, oSubTstDrv):
421 _ = oSubTstDrv;
422 reporter.log2('Deleting directory "%s" ...' % (limitString(self.sPath),));
423 try:
424 self.oGuestSession.directoryRemove(self.sPath);
425 except:
426 reporter.maybeErrXcpt(self.fRcExpect, 'Removing "%s" (as a directory) failed' % (self.sPath,));
427 return not self.fRcExpect;
428 if not self.fRcExpect:
429 return reporter.error('Expected removing "%s" (dir) to failed, but it succeeded' % (self.sPath,));
430
431 return self.checkRemoved('directory');
432
433class tdTestRemoveTree(tdTestRemoveBase):
434 """
435 Recursively remove a directory tree.
436 """
437 def __init__(self, sPath, afFlags = None, fRcExpect = True, fNotExist = False, oCreds = None):
438 tdTestRemoveBase.__init__(self, sPath, fRcExpect, oCreds = None);
439 self.afFlags = afFlags if afFlags is not None else [];
440 self.fNotExist = fNotExist; # Hack for the ContentOnly scenario where the dir does not exist.
441
442 def execute(self, oSubTstDrv):
443 reporter.log2('Deleting tree "%s" ...' % (limitString(self.sPath),));
444 try:
445 oProgress = self.oGuestSession.directoryRemoveRecursive(self.sPath, self.afFlags);
446 except:
447 reporter.maybeErrXcpt(self.fRcExpect, 'Removing directory tree "%s" failed (afFlags=%s)'
448 % (self.sPath, self.afFlags));
449 return not self.fRcExpect;
450
451 oWrappedProgress = vboxwrappers.ProgressWrapper(oProgress, oSubTstDrv.oTstDrv.oVBoxMgr, oSubTstDrv.oTstDrv,
452 "remove-tree: %s" % (self.sPath,));
453 oWrappedProgress.wait();
454 if not oWrappedProgress.isSuccess():
455 oWrappedProgress.logResult(fIgnoreErrors = not self.fRcExpect);
456 return not self.fRcExpect;
457 if not self.fRcExpect:
458 return reporter.error('Expected removing "%s" (tree) to failed, but it succeeded' % (self.sPath,));
459
460 if vboxcon.DirectoryRemoveRecFlag_ContentAndDir not in self.afFlags and not self.fNotExist:
461 # Cannot use directoryExists here as it is buggy.
462 try:
463 if oSubTstDrv.oTstDrv.fpApiVer >= 5.0:
464 oFsObjInfo = self.oGuestSession.fsObjQueryInfo(self.sPath, False);
465 else:
466 oFsObjInfo = self.oGuestSession.fileQueryInfo(self.sPath);
467 eType = oFsObjInfo.type;
468 except:
469 return reporter.errorXcpt('sPath=%s' % (self.sPath,));
470 if eType != vboxcon.FsObjType_Directory:
471 return reporter.error('Found file type %d, expected directory (%d) for %s after rmtree/OnlyContent'
472 % (eType, vboxcon.FsObjType_Directory, self.sPath,));
473 return True;
474
475 return self.checkRemoved('tree');
476
477
478class tdTestFileStat(tdTestGuestCtrlBase):
479 """
480 Test querying guest file information.
481 """
482 def __init__(self, sFile = "", oCreds = None, cbSize = 0, eFileType = 0):
483 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
484 self.sFile = sFile;
485 self.cbSize = cbSize;
486 self.eFileType = eFileType;
487
488class tdTestFileIO(tdTestGuestCtrlBase):
489 """
490 Test for the IGuestFile object.
491 """
492 def __init__(self, sFile = "", oCreds = None):
493 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
494 self.sFile = sFile;
495
496class tdTestFileQuerySize(tdTestGuestCtrlBase):
497 """
498 Test for the file size query API call (fileQuerySize).
499 """
500 def __init__(self, sFile = "", oCreds = None):
501 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
502 self.sFile = sFile;
503
504class tdTestFileOpen(tdTestGuestCtrlBase):
505 """
506 Tests opening a guest files.
507 """
508 def __init__(self, sFile = "", eAccessMode = None, eAction = None, eSharing = None,
509 fCreationMode = 0o660, oCreds = None):
510 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
511 self.sFile = sFile;
512 self.eAccessMode = eAccessMode if eAccessMode is not None else vboxcon.FileAccessMode_ReadOnly;
513 self.eAction = eAction if eAction is not None else vboxcon.FileOpenAction_OpenExisting;
514 self.eSharing = eSharing if eSharing is not None else vboxcon.FileSharingMode_All;
515 self.fCreationMode = fCreationMode;
516 self.afOpenFlags = [];
517 self.oOpenedFile = None;
518
519 def toString(self):
520 """ Get a summary string. """
521 return 'eAccessMode=%s eAction=%s sFile=%s' % (self.eAccessMode, self.eAction, self.sFile);
522
523 def doOpenStep(self, fExpectSuccess):
524 """
525 Does the open step, putting the resulting file in oOpenedFile.
526 """
527 try:
528 self.oOpenedFile = self.oGuestSession.fileOpenEx(self.sFile, self.eAccessMode, self.eAction,
529 self.eSharing, self.fCreationMode, self.afOpenFlags);
530 except:
531 reporter.maybeErrXcpt(fExpectSuccess, 'fileOpenEx(%s, %s, %s, %s, %s, %s)'
532 % (self.sFile, self.eAccessMode, self.eAction, self.eSharing,
533 self.fCreationMode, self.afOpenFlags,));
534 return False;
535 return True;
536
537 def doStepsOnOpenedFile(self, fExpectSuccess, oSubTst):
538 """ Overridden by children to do more testing. """
539 _ = fExpectSuccess; _ = oSubTst;
540 return True;
541
542 def doCloseStep(self):
543 """ Closes the file. """
544 if self.oOpenedFile:
545 try:
546 self.oOpenedFile.close();
547 except:
548 return reporter.errorXcpt('close([%s, %s, %s, %s, %s, %s])'
549 % (self.sFile, self.eAccessMode, self.eAction, self.eSharing,
550 self.fCreationMode, self.afOpenFlags,));
551 self.oOpenedFile = None;
552 return True;
553
554 def doSteps(self, fExpectSuccess, oSubTst):
555 """ Do the tests. """
556 fRc = self.doOpenStep(fExpectSuccess);
557 if fRc is True:
558 fRc = self.doStepsOnOpenedFile(fExpectSuccess, oSubTst);
559 if self.oOpenedFile:
560 fRc = self.doCloseStep() and fRc;
561 return fRc;
562
563
564class tdTestFileOpenCheckSize(tdTestFileOpen):
565 """
566 Opens a file and checks the size.
567 """
568 def __init__(self, sFile = "", eAccessMode = None, eAction = None, eSharing = None,
569 fCreationMode = 0o660, cbOpenExpected = 0, oCreds = None):
570 tdTestFileOpen.__init__(self, sFile, eAccessMode, eAction, eSharing, fCreationMode, oCreds);
571 self.cbOpenExpected = cbOpenExpected;
572
573 def toString(self):
574 return 'cbOpenExpected=%s %s' % (self.cbOpenExpected, tdTestFileOpen.toString(self),);
575
576 def doStepsOnOpenedFile(self, fExpectSuccess, oSubTst):
577 #
578 # Call parent.
579 #
580 fRc = tdTestFileOpen.doStepsOnOpenedFile(self, fExpectSuccess, oSubTst);
581
582 #
583 # Check the size. Requires 6.0 or later (E_NOTIMPL in 5.2).
584 #
585 if oSubTst.oTstDrv.fpApiVer >= 6.0:
586 try:
587 oFsObjInfo = self.oOpenedFile.queryInfo();
588 except:
589 return reporter.errorXcpt('queryInfo([%s, %s, %s, %s, %s, %s])'
590 % (self.sFile, self.eAccessMode, self.eAction, self.eSharing,
591 self.fCreationMode, self.afOpenFlags,));
592 if oFsObjInfo is None:
593 return reporter.error('IGuestFile::queryInfo returned None');
594 try:
595 cbFile = oFsObjInfo.objectSize;
596 except:
597 return reporter.errorXcpt();
598 if cbFile != self.cbOpenExpected:
599 return reporter.error('Wrong file size after open (%d): %s, expected %s (file %s) (#1)'
600 % (self.eAction, cbFile, self.cbOpenExpected, self.sFile));
601
602 try:
603 cbFile = self.oOpenedFile.querySize();
604 except:
605 return reporter.errorXcpt('querySize([%s, %s, %s, %s, %s, %s])'
606 % (self.sFile, self.eAccessMode, self.eAction, self.eSharing,
607 self.fCreationMode, self.afOpenFlags,));
608 if cbFile != self.cbOpenExpected:
609 return reporter.error('Wrong file size after open (%d): %s, expected %s (file %s) (#2)'
610 % (self.eAction, cbFile, self.cbOpenExpected, self.sFile));
611
612 return fRc;
613
614
615class tdTestFileOpenAndWrite(tdTestFileOpen):
616 """
617 Opens the file and writes one or more chunks to it.
618
619 The chunks are a list of tuples(offset, bytes), where offset can be None
620 if no seeking should be performed.
621 """
622 def __init__(self, sFile = "", eAccessMode = None, eAction = None, eSharing = None, # pylint: disable=too-many-arguments
623 fCreationMode = 0o660, atChunks = None, fUseAtApi = False, abContent = None, oCreds = None):
624 tdTestFileOpen.__init__(self, sFile, eAccessMode if eAccessMode is not None else vboxcon.FileAccessMode_WriteOnly,
625 eAction, eSharing, fCreationMode, oCreds);
626 assert atChunks is not None;
627 self.atChunks = atChunks # type: list(tuple(int,bytearray))
628 self.fUseAtApi = fUseAtApi;
629 self.fAppend = ( eAccessMode in (vboxcon.FileAccessMode_AppendOnly, vboxcon.FileAccessMode_AppendRead)
630 or eAction == vboxcon.FileOpenAction_AppendOrCreate);
631 self.abContent = abContent # type: bytearray
632
633 def toString(self):
634 sChunks = ', '.join('%s LB %s' % (tChunk[0], len(tChunk[1]),) for tChunk in self.atChunks);
635 sApi = 'writeAt' if self.fUseAtApi else 'write';
636 return '%s [%s] %s' % (sApi, sChunks, tdTestFileOpen.toString(self),);
637
638 def doStepsOnOpenedFile(self, fExpectSuccess, oSubTst):
639 #
640 # Call parent.
641 #
642 fRc = tdTestFileOpen.doStepsOnOpenedFile(self, fExpectSuccess, oSubTst);
643
644 #
645 # Do the writing.
646 #
647 for offFile, abBuf in self.atChunks:
648 if self.fUseAtApi:
649 #
650 # writeAt:
651 #
652 assert offFile is not None;
653 reporter.log2('writeAt(%s, %s bytes)' % (offFile, len(abBuf),));
654 if self.fAppend:
655 if self.abContent is not None: # Try avoid seek as it updates the cached offset in GuestFileImpl.
656 offExpectAfter = len(self.abContent);
657 else:
658 try:
659 offSave = self.oOpenedFile.seek(0, vboxcon.FileSeekOrigin_Current);
660 offExpectAfter = self.oOpenedFile.seek(0, vboxcon.FileSeekOrigin_End);
661 self.oOpenedFile.seek(offSave, vboxcon.FileSeekOrigin_Begin);
662 except:
663 return reporter.errorXcpt();
664 offExpectAfter += len(abBuf);
665 else:
666 offExpectAfter = offFile + len(abBuf);
667
668 try:
669 cbWritten = self.oOpenedFile.writeAt(offFile, abBuf, 30*1000);
670 except:
671 return reporter.errorXcpt('writeAt(%s, %s bytes)' % (offFile, len(abBuf),));
672
673 else:
674 #
675 # write:
676 #
677 if self.fAppend:
678 if self.abContent is not None: # Try avoid seek as it updates the cached offset in GuestFileImpl.
679 offExpectAfter = len(self.abContent);
680 else:
681 try:
682 offSave = self.oOpenedFile.seek(0, vboxcon.FileSeekOrigin_Current);
683 offExpectAfter = self.oOpenedFile.seek(0, vboxcon.FileSeekOrigin_End);
684 self.oOpenedFile.seek(offSave, vboxcon.FileSeekOrigin_Begin);
685 except:
686 return reporter.errorXcpt('seek(0,End)');
687 if offFile is not None:
688 try:
689 self.oOpenedFile.seek(offFile, vboxcon.FileSeekOrigin_Begin);
690 except:
691 return reporter.errorXcpt('seek(%s,Begin)' % (offFile,));
692 else:
693 try:
694 offFile = self.oOpenedFile.seek(0, vboxcon.FileSeekOrigin_Current);
695 except:
696 return reporter.errorXcpt();
697 if not self.fAppend:
698 offExpectAfter = offFile;
699 offExpectAfter += len(abBuf);
700
701 reporter.log2('write(%s bytes @ %s)' % (len(abBuf), offFile,));
702 try:
703 cbWritten = self.oOpenedFile.write(abBuf, 30*1000);
704 except:
705 return reporter.errorXcpt('write(%s bytes @ %s)' % (len(abBuf), offFile));
706
707 #
708 # Check how much was written, ASSUMING nothing we push thru here is too big:
709 #
710 if cbWritten != len(abBuf):
711 fRc = reporter.errorXcpt('Wrote less than expected: %s out of %s, expected all to be written'
712 % (cbWritten, len(abBuf),));
713 if not self.fAppend:
714 offExpectAfter -= len(abBuf) - cbWritten;
715
716 #
717 # Update the file content tracker if we've got one and can:
718 #
719 if self.abContent is not None:
720 if cbWritten < len(abBuf):
721 abBuf = abBuf[:cbWritten];
722
723 #
724 # In append mode, the current file offset shall be disregarded and the
725 # write always goes to the end of the file, regardless of writeAt or write.
726 # Note that RTFileWriteAt only naturally behaves this way on linux and
727 # (probably) windows, so VBoxService makes that behaviour generic across
728 # all OSes.
729 #
730 if self.fAppend:
731 reporter.log2('len(self.abContent)=%s + %s' % (len(self.abContent), cbWritten, ));
732 self.abContent.extend(abBuf);
733 else:
734 if offFile is None:
735 offFile = offExpectAfter - cbWritten;
736 reporter.log2('len(self.abContent)=%s + %s @ %s' % (len(self.abContent), cbWritten, offFile, ));
737 if offFile > len(self.abContent):
738 self.abContent.extend(bytearray(offFile - len(self.abContent)));
739 self.abContent[offFile:offFile + cbWritten] = abBuf;
740 reporter.log2('len(self.abContent)=%s' % (len(self.abContent),));
741
742 #
743 # Check the resulting file offset with IGuestFile::offset.
744 #
745 try:
746 offApi = self.oOpenedFile.offset; # Must be gotten first!
747 offSeek = self.oOpenedFile.seek(0, vboxcon.FileSeekOrigin_Current);
748 except:
749 fRc = reporter.errorXcpt();
750 else:
751 reporter.log2('offApi=%s offSeek=%s offExpectAfter=%s' % (offApi, offSeek, offExpectAfter,));
752 if offSeek != offExpectAfter:
753 fRc = reporter.error('Seek offset is %s, expected %s after %s bytes write @ %s (offApi=%s)'
754 % (offSeek, offExpectAfter, len(abBuf), offFile, offApi,));
755 if offApi != offExpectAfter:
756 fRc = reporter.error('IGuestFile::offset is %s, expected %s after %s bytes write @ %s (offSeek=%s)'
757 % (offApi, offExpectAfter, len(abBuf), offFile, offSeek,));
758 # for each chunk - end
759 return fRc;
760
761
762class tdTestFileOpenAndCheckContent(tdTestFileOpen):
763 """
764 Opens the file and checks the content using the read API.
765 """
766 def __init__(self, sFile = "", eSharing = None, abContent = None, cbContentExpected = None, oCreds = None):
767 tdTestFileOpen.__init__(self, sFile = sFile, eSharing = eSharing, oCreds = oCreds);
768 self.abContent = abContent # type: bytearray
769 self.cbContentExpected = cbContentExpected;
770
771 def toString(self):
772 return 'check content %s (%s) %s' % (len(self.abContent), self.cbContentExpected, tdTestFileOpen.toString(self),);
773
774 def doStepsOnOpenedFile(self, fExpectSuccess, oSubTst):
775 #
776 # Call parent.
777 #
778 fRc = tdTestFileOpen.doStepsOnOpenedFile(self, fExpectSuccess, oSubTst);
779
780 #
781 # Check the expected content size.
782 #
783 if self.cbContentExpected is not None:
784 if len(self.abContent) != self.cbContentExpected:
785 fRc = reporter.error('Incorrect abContent size: %s, expected %s'
786 % (len(self.abContent), self.cbContentExpected,));
787
788 #
789 # Read the file and compare it with the content.
790 #
791 offFile = 0;
792 while True:
793 try:
794 abChunk = self.oOpenedFile.read(512*1024, 30*1000);
795 except:
796 return reporter.errorXcpt('read(512KB) @ %s' % (offFile,));
797 cbChunk = len(abChunk);
798 if cbChunk == 0:
799 if offFile != len(self.abContent):
800 fRc = reporter.error('Unexpected EOF @ %s, len(abContent)=%s' % (offFile, len(self.abContent),));
801 break;
802 if offFile + cbChunk > len(self.abContent):
803 fRc = reporter.error('File is larger than expected: at least %s bytes, expected %s bytes'
804 % (offFile + cbChunk, len(self.abContent),));
805 elif not utils.areBytesEqual(abChunk, self.abContent[offFile:(offFile + cbChunk)]):
806 fRc = reporter.error('Mismatch in range %s LB %s!' % (offFile, cbChunk,));
807 offFile += cbChunk;
808
809 return fRc;
810
811
812class tdTestSession(tdTestGuestCtrlBase):
813 """
814 Test the guest session handling.
815 """
816 def __init__(self, sUser = None, sPassword = None, sDomain = None, sSessionName = ""):
817 tdTestGuestCtrlBase.__init__(self, oCreds = tdCtxCreds(sUser, sPassword, sDomain));
818 self.sSessionName = sSessionName;
819
820 def getSessionCount(self, oVBoxMgr):
821 """
822 Helper for returning the number of currently
823 opened guest sessions of a VM.
824 """
825 if self.oGuest is None:
826 return 0;
827 try:
828 aoSession = oVBoxMgr.getArray(self.oGuest, 'sessions')
829 except:
830 reporter.errorXcpt('sSessionName: %s' % (self.sSessionName,));
831 return 0;
832 return len(aoSession);
833
834
835class tdTestSessionEx(tdTestGuestCtrlBase):
836 """
837 Test the guest session.
838 """
839 def __init__(self, aoSteps = None, enmUser = None):
840 tdTestGuestCtrlBase.__init__(self);
841 assert enmUser is None; # For later.
842 self.enmUser = enmUser;
843 self.aoSteps = aoSteps if aoSteps is not None else [];
844
845 def execute(self, oTstDrv, oVmSession, oTxsSession, oTestVm, sMsgPrefix):
846 """
847 Executes the test.
848 """
849 #
850 # Create a session.
851 #
852 assert self.enmUser is None; # For later.
853 self.oCreds = tdCtxCreds();
854 self.setEnvironment(oVmSession, oTxsSession, oTestVm);
855 reporter.log2('%s: %s steps' % (sMsgPrefix, len(self.aoSteps),));
856 fRc, oCurSession = self.createSession(sMsgPrefix);
857 if fRc is True:
858 #
859 # Execute the tests.
860 #
861 try:
862 fRc = self.executeSteps(oTstDrv, oCurSession, sMsgPrefix);
863 except:
864 fRc = reporter.errorXcpt('%s: Unexpected exception executing test steps' % (sMsgPrefix,));
865
866 #
867 # Close the session.
868 #
869 fRc2 = self.closeSession();
870 if fRc2 is False:
871 fRc = reporter.error('%s: Session could not be closed' % (sMsgPrefix,));
872 else:
873 fRc = reporter.error('%s: Session creation failed' % (sMsgPrefix,));
874 return fRc;
875
876 def executeSteps(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
877 """
878 Executes just the steps.
879 Returns True on success, False on test failure.
880 """
881 fRc = True;
882 for (i, oStep) in enumerate(self.aoSteps):
883 fRc2 = oStep.execute(oTstDrv, oGstCtrlSession, sMsgPrefix + ', step #%d' % i);
884 if fRc2 is True:
885 pass;
886 elif fRc2 is None:
887 reporter.log('%s: skipping remaining %d steps' % (sMsgPrefix, len(self.aoSteps) - i - 1,));
888 break;
889 else:
890 fRc = False;
891 return fRc;
892
893 @staticmethod
894 def executeListTestSessions(aoTests, oTstDrv, oVmSession, oTxsSession, oTestVm, sMsgPrefix):
895 """
896 Works thru a list of tdTestSessionEx object.
897 """
898 fRc = True;
899 for (i, oCurTest) in enumerate(aoTests):
900 try:
901 fRc2 = oCurTest.execute(oTstDrv, oVmSession, oTxsSession, oTestVm, '%s / %#d' % (sMsgPrefix, i,));
902 if fRc2 is not True:
903 fRc = False;
904 except:
905 fRc = reporter.errorXcpt('%s: Unexpected exception executing test #%d' % (sMsgPrefix, i ,));
906
907 return (fRc, oTxsSession);
908
909
910class tdSessionStepBase(object):
911 """
912 Base class for the guest control session test steps.
913 """
914
915 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
916 """
917 Executes the test step.
918
919 Returns True on success.
920 Returns False on failure (must be reported as error).
921 Returns None if to skip the remaining steps.
922 """
923 _ = oTstDrv;
924 _ = oGstCtrlSession;
925 return reporter.error('%s: Missing execute implementation: %s' % (sMsgPrefix, self,));
926
927
928class tdStepRequireMinimumApiVer(tdSessionStepBase):
929 """
930 Special test step which will cause executeSteps to skip the remaining step
931 if the VBox API is too old:
932 """
933 def __init__(self, fpMinApiVer):
934 self.fpMinApiVer = fpMinApiVer;
935
936 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
937 """ Returns None if API version is too old, otherwise True. """
938 if oTstDrv.fpApiVer >= self.fpMinApiVer:
939 return True;
940 _ = oGstCtrlSession;
941 _ = sMsgPrefix;
942 return None; # Special return value. Don't use elsewhere.
943
944
945#
946# Scheduling Environment Changes with the Guest Control Session.
947#
948
949class tdStepSessionSetEnv(tdSessionStepBase):
950 """
951 Guest session environment: schedule putenv
952 """
953 def __init__(self, sVar, sValue, hrcExpected = 0):
954 self.sVar = sVar;
955 self.sValue = sValue;
956 self.hrcExpected = hrcExpected;
957
958 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
959 """
960 Executes the step.
961 Returns True on success, False on test failure.
962 """
963 reporter.log2('tdStepSessionSetEnv: sVar=%s sValue=%s hrcExpected=%#x' % (self.sVar, self.sValue, self.hrcExpected,));
964 try:
965 if oTstDrv.fpApiVer >= 5.0:
966 oGstCtrlSession.environmentScheduleSet(self.sVar, self.sValue);
967 else:
968 oGstCtrlSession.environmentSet(self.sVar, self.sValue);
969 except vbox.ComException as oXcpt:
970 # Is this an expected failure?
971 if vbox.ComError.equal(oXcpt, self.hrcExpected):
972 return True;
973 return reporter.errorXcpt('%s: Expected hrc=%#x (%s) got %#x (%s) instead (setenv %s=%s)'
974 % (sMsgPrefix, self.hrcExpected, vbox.ComError.toString(self.hrcExpected),
975 vbox.ComError.getXcptResult(oXcpt),
976 vbox.ComError.toString(vbox.ComError.getXcptResult(oXcpt)),
977 self.sVar, self.sValue,));
978 except:
979 return reporter.errorXcpt('%s: Unexpected exception in tdStepSessionSetEnv::execute (%s=%s)'
980 % (sMsgPrefix, self.sVar, self.sValue,));
981
982 # Should we succeed?
983 if self.hrcExpected != 0:
984 return reporter.error('%s: Expected hrcExpected=%#x, got S_OK (putenv %s=%s)'
985 % (sMsgPrefix, self.hrcExpected, self.sVar, self.sValue,));
986 return True;
987
988class tdStepSessionUnsetEnv(tdSessionStepBase):
989 """
990 Guest session environment: schedule unset.
991 """
992 def __init__(self, sVar, hrcExpected = 0):
993 self.sVar = sVar;
994 self.hrcExpected = hrcExpected;
995
996 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
997 """
998 Executes the step.
999 Returns True on success, False on test failure.
1000 """
1001 reporter.log2('tdStepSessionUnsetEnv: sVar=%s hrcExpected=%#x' % (self.sVar, self.hrcExpected,));
1002 try:
1003 if oTstDrv.fpApiVer >= 5.0:
1004 oGstCtrlSession.environmentScheduleUnset(self.sVar);
1005 else:
1006 oGstCtrlSession.environmentUnset(self.sVar);
1007 except vbox.ComException as oXcpt:
1008 # Is this an expected failure?
1009 if vbox.ComError.equal(oXcpt, self.hrcExpected):
1010 return True;
1011 return reporter.errorXcpt('%s: Expected hrc=%#x (%s) got %#x (%s) instead (unsetenv %s)'
1012 % (sMsgPrefix, self.hrcExpected, vbox.ComError.toString(self.hrcExpected),
1013 vbox.ComError.getXcptResult(oXcpt),
1014 vbox.ComError.toString(vbox.ComError.getXcptResult(oXcpt)),
1015 self.sVar,));
1016 except:
1017 return reporter.errorXcpt('%s: Unexpected exception in tdStepSessionUnsetEnv::execute (%s)'
1018 % (sMsgPrefix, self.sVar,));
1019
1020 # Should we succeed?
1021 if self.hrcExpected != 0:
1022 return reporter.error('%s: Expected hrcExpected=%#x, got S_OK (unsetenv %s)'
1023 % (sMsgPrefix, self.hrcExpected, self.sVar,));
1024 return True;
1025
1026class tdStepSessionBulkEnv(tdSessionStepBase):
1027 """
1028 Guest session environment: Bulk environment changes.
1029 """
1030 def __init__(self, asEnv = None, hrcExpected = 0):
1031 self.asEnv = asEnv if asEnv is not None else [];
1032 self.hrcExpected = hrcExpected;
1033
1034 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
1035 """
1036 Executes the step.
1037 Returns True on success, False on test failure.
1038 """
1039 reporter.log2('tdStepSessionBulkEnv: asEnv=%s hrcExpected=%#x' % (self.asEnv, self.hrcExpected,));
1040 try:
1041 if oTstDrv.fpApiVer >= 5.0:
1042 oTstDrv.oVBoxMgr.setArray(oGstCtrlSession, 'environmentChanges', self.asEnv);
1043 else:
1044 oTstDrv.oVBoxMgr.setArray(oGstCtrlSession, 'environment', self.asEnv);
1045 except vbox.ComException as oXcpt:
1046 # Is this an expected failure?
1047 if vbox.ComError.equal(oXcpt, self.hrcExpected):
1048 return True;
1049 return reporter.errorXcpt('%s: Expected hrc=%#x (%s) got %#x (%s) instead (asEnv=%s)'
1050 % (sMsgPrefix, self.hrcExpected, vbox.ComError.toString(self.hrcExpected),
1051 vbox.ComError.getXcptResult(oXcpt),
1052 vbox.ComError.toString(vbox.ComError.getXcptResult(oXcpt)),
1053 self.asEnv,));
1054 except:
1055 return reporter.errorXcpt('%s: Unexpected exception writing the environmentChanges property (asEnv=%s).'
1056 % (sMsgPrefix, self.asEnv));
1057 return True;
1058
1059class tdStepSessionClearEnv(tdStepSessionBulkEnv):
1060 """
1061 Guest session environment: clears the scheduled environment changes.
1062 """
1063 def __init__(self):
1064 tdStepSessionBulkEnv.__init__(self);
1065
1066
1067class tdStepSessionCheckEnv(tdSessionStepBase):
1068 """
1069 Check the currently scheduled environment changes of a guest control session.
1070 """
1071 def __init__(self, asEnv = None):
1072 self.asEnv = asEnv if asEnv is not None else [];
1073
1074 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
1075 """
1076 Executes the step.
1077 Returns True on success, False on test failure.
1078 """
1079 reporter.log2('tdStepSessionCheckEnv: asEnv=%s' % (self.asEnv,));
1080
1081 #
1082 # Get the environment change list.
1083 #
1084 try:
1085 if oTstDrv.fpApiVer >= 5.0:
1086 asCurEnv = oTstDrv.oVBoxMgr.getArray(oGstCtrlSession, 'environmentChanges');
1087 else:
1088 asCurEnv = oTstDrv.oVBoxMgr.getArray(oGstCtrlSession, 'environment');
1089 except:
1090 return reporter.errorXcpt('%s: Unexpected exception reading the environmentChanges property.' % (sMsgPrefix,));
1091
1092 #
1093 # Compare it with the expected one by trying to remove each expected value
1094 # and the list anything unexpected.
1095 #
1096 fRc = True;
1097 asCopy = list(asCurEnv); # just in case asCurEnv is immutable
1098 for sExpected in self.asEnv:
1099 try:
1100 asCopy.remove(sExpected);
1101 except:
1102 fRc = reporter.error('%s: Expected "%s" to be in the resulting environment' % (sMsgPrefix, sExpected,));
1103 for sUnexpected in asCopy:
1104 fRc = reporter.error('%s: Unexpected "%s" in the resulting environment' % (sMsgPrefix, sUnexpected,));
1105
1106 if fRc is not True:
1107 reporter.log2('%s: Current environment: %s' % (sMsgPrefix, asCurEnv));
1108 return fRc;
1109
1110
1111#
1112# File system object statistics (i.e. stat()).
1113#
1114
1115class tdStepStat(tdSessionStepBase):
1116 """
1117 Stats a file system object.
1118 """
1119 def __init__(self, sPath, hrcExpected = 0, fFound = True, fFollowLinks = True, enmType = None, oTestFsObj = None):
1120 self.sPath = sPath;
1121 self.hrcExpected = hrcExpected;
1122 self.fFound = fFound;
1123 self.fFollowLinks = fFollowLinks;
1124 self.enmType = enmType if enmType is not None else vboxcon.FsObjType_File;
1125 self.cbExactSize = None;
1126 self.cbMinSize = None;
1127 self.oTestFsObj = oTestFsObj # type: testfileset.TestFsObj
1128
1129 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
1130 """
1131 Execute the test step.
1132 """
1133 reporter.log2('tdStepStat: sPath=%s enmType=%s hrcExpected=%s fFound=%s fFollowLinks=%s'
1134 % (limitString(self.sPath), self.enmType, self.hrcExpected, self.fFound, self.fFollowLinks,));
1135
1136 # Don't execute non-file tests on older VBox version.
1137 if oTstDrv.fpApiVer >= 5.0 or self.enmType == vboxcon.FsObjType_File or not self.fFound:
1138 #
1139 # Call the API.
1140 #
1141 try:
1142 if oTstDrv.fpApiVer >= 5.0:
1143 oFsInfo = oGstCtrlSession.fsObjQueryInfo(self.sPath, self.fFollowLinks);
1144 else:
1145 oFsInfo = oGstCtrlSession.fileQueryInfo(self.sPath);
1146 except vbox.ComException as oXcpt:
1147 ## @todo: The error reporting in the API just plain sucks! Most of the errors are
1148 ## VBOX_E_IPRT_ERROR and there seems to be no way to distinguish between
1149 ## non-existing files/path and a lot of other errors. Fix API and test!
1150 if not self.fFound:
1151 return True;
1152 if vbox.ComError.equal(oXcpt, self.hrcExpected): # Is this an expected failure?
1153 return True;
1154 return reporter.errorXcpt('%s: Unexpected exception for exiting path "%s" (enmType=%s, hrcExpected=%s):'
1155 % (sMsgPrefix, self.sPath, self.enmType, self.hrcExpected,));
1156 except:
1157 return reporter.errorXcpt('%s: Unexpected exception in tdStepStat::execute (%s)'
1158 % (sMsgPrefix, self.sPath,));
1159 if oFsInfo is None:
1160 return reporter.error('%s: "%s" got None instead of IFsObjInfo instance!' % (sMsgPrefix, self.sPath,));
1161
1162 #
1163 # Check type expectations.
1164 #
1165 try:
1166 enmType = oFsInfo.type;
1167 except:
1168 return reporter.errorXcpt('%s: Unexpected exception in reading "IFsObjInfo::type"' % (sMsgPrefix,));
1169 if enmType != self.enmType:
1170 return reporter.error('%s: "%s" has type %s, expected %s'
1171 % (sMsgPrefix, self.sPath, enmType, self.enmType));
1172
1173 #
1174 # Check size expectations.
1175 # Note! This is unicode string here on windows, for some reason.
1176 # long long mapping perhaps?
1177 #
1178 try:
1179 cbObject = long(oFsInfo.objectSize);
1180 except:
1181 return reporter.errorXcpt('%s: Unexpected exception in reading "IFsObjInfo::objectSize"'
1182 % (sMsgPrefix,));
1183 if self.cbExactSize is not None \
1184 and cbObject != self.cbExactSize:
1185 return reporter.error('%s: "%s" has size %s bytes, expected %s bytes'
1186 % (sMsgPrefix, self.sPath, cbObject, self.cbExactSize));
1187 if self.cbMinSize is not None \
1188 and cbObject < self.cbMinSize:
1189 return reporter.error('%s: "%s" has size %s bytes, expected as least %s bytes'
1190 % (sMsgPrefix, self.sPath, cbObject, self.cbMinSize));
1191 return True;
1192
1193class tdStepStatDir(tdStepStat):
1194 """ Checks for an existing directory. """
1195 def __init__(self, sDirPath, oTestDir = None):
1196 tdStepStat.__init__(self, sPath = sDirPath, enmType = vboxcon.FsObjType_Directory, oTestFsObj = oTestDir);
1197
1198class tdStepStatDirEx(tdStepStatDir):
1199 """ Checks for an existing directory given a TestDir object. """
1200 def __init__(self, oTestDir): # type: (testfileset.TestDir)
1201 tdStepStatDir.__init__(self, oTestDir.sPath, oTestDir);
1202
1203class tdStepStatFile(tdStepStat):
1204 """ Checks for an existing file """
1205 def __init__(self, sFilePath = None, oTestFile = None):
1206 tdStepStat.__init__(self, sPath = sFilePath, enmType = vboxcon.FsObjType_File, oTestFsObj = oTestFile);
1207
1208class tdStepStatFileEx(tdStepStatFile):
1209 """ Checks for an existing file given a TestFile object. """
1210 def __init__(self, oTestFile): # type: (testfileset.TestFile)
1211 tdStepStatFile.__init__(self, oTestFile.sPath, oTestFile);
1212
1213class tdStepStatFileSize(tdStepStat):
1214 """ Checks for an existing file of a given expected size.. """
1215 def __init__(self, sFilePath, cbExactSize = 0):
1216 tdStepStat.__init__(self, sPath = sFilePath, enmType = vboxcon.FsObjType_File);
1217 self.cbExactSize = cbExactSize;
1218
1219class tdStepStatFileNotFound(tdStepStat):
1220 """ Checks for an existing directory. """
1221 def __init__(self, sPath):
1222 tdStepStat.__init__(self, sPath = sPath, fFound = False);
1223
1224class tdStepStatPathNotFound(tdStepStat):
1225 """ Checks for an existing directory. """
1226 def __init__(self, sPath):
1227 tdStepStat.__init__(self, sPath = sPath, fFound = False);
1228
1229
1230#
1231#
1232#
1233
1234class tdTestSessionFileRefs(tdTestGuestCtrlBase):
1235 """
1236 Tests session file (IGuestFile) reference counting.
1237 """
1238 def __init__(self, cRefs = 0):
1239 tdTestGuestCtrlBase.__init__(self);
1240 self.cRefs = cRefs;
1241
1242class tdTestSessionDirRefs(tdTestGuestCtrlBase):
1243 """
1244 Tests session directory (IGuestDirectory) reference counting.
1245 """
1246 def __init__(self, cRefs = 0):
1247 tdTestGuestCtrlBase.__init__(self);
1248 self.cRefs = cRefs;
1249
1250class tdTestSessionProcRefs(tdTestGuestCtrlBase):
1251 """
1252 Tests session process (IGuestProcess) reference counting.
1253 """
1254 def __init__(self, cRefs = 0):
1255 tdTestGuestCtrlBase.__init__(self);
1256 self.cRefs = cRefs;
1257
1258class tdTestUpdateAdditions(tdTestGuestCtrlBase):
1259 """
1260 Test updating the Guest Additions inside the guest.
1261 """
1262 def __init__(self, sSrc = "", asArgs = None, afFlags = None, oCreds = None):
1263 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
1264 self.sSrc = sSrc;
1265 self.asArgs = asArgs;
1266 self.afFlags = afFlags;
1267
1268class tdTestResult(object):
1269 """
1270 Base class for test results.
1271 """
1272 def __init__(self, fRc = False):
1273 ## The overall test result.
1274 self.fRc = fRc;
1275
1276class tdTestResultFailure(tdTestResult):
1277 """
1278 Base class for test results.
1279 """
1280 def __init__(self):
1281 tdTestResult.__init__(self, fRc = False);
1282
1283class tdTestResultSuccess(tdTestResult):
1284 """
1285 Base class for test results.
1286 """
1287 def __init__(self):
1288 tdTestResult.__init__(self, fRc = True);
1289
1290class tdTestResultDirRead(tdTestResult):
1291 """
1292 Test result for reading guest directories.
1293 """
1294 def __init__(self, fRc = False, cFiles = 0, cDirs = 0, cOthers = None):
1295 tdTestResult.__init__(self, fRc = fRc);
1296 self.cFiles = cFiles;
1297 self.cDirs = cDirs;
1298 self.cOthers = cOthers;
1299
1300class tdTestResultExec(tdTestResult):
1301 """
1302 Holds a guest process execution test result,
1303 including the exit code, status + afFlags.
1304 """
1305 def __init__(self, fRc = False, uExitStatus = 500, iExitCode = 0, sBuf = None, cbBuf = 0, cbStdOut = None, cbStdErr = None):
1306 tdTestResult.__init__(self);
1307 ## The overall test result.
1308 self.fRc = fRc;
1309 ## Process exit stuff.
1310 self.uExitStatus = uExitStatus;
1311 self.iExitCode = iExitCode;
1312 ## Desired buffer length returned back from stdout/stderr.
1313 self.cbBuf = cbBuf;
1314 ## Desired buffer result from stdout/stderr. Use with caution!
1315 self.sBuf = sBuf;
1316 self.cbStdOut = cbStdOut;
1317 self.cbStdErr = cbStdErr;
1318
1319class tdTestResultFileStat(tdTestResult):
1320 """
1321 Test result for stat'ing guest files.
1322 """
1323 def __init__(self, fRc = False,
1324 cbSize = 0, eFileType = 0):
1325 tdTestResult.__init__(self, fRc = fRc);
1326 self.cbSize = cbSize;
1327 self.eFileType = eFileType;
1328 ## @todo Add more information.
1329
1330class tdTestResultFileReadWrite(tdTestResult):
1331 """
1332 Test result for reading + writing guest directories.
1333 """
1334 def __init__(self, fRc = False,
1335 cbProcessed = 0, offFile = 0, abBuf = None):
1336 tdTestResult.__init__(self, fRc = fRc);
1337 self.cbProcessed = cbProcessed;
1338 self.offFile = offFile;
1339 self.abBuf = abBuf;
1340
1341class tdTestResultSession(tdTestResult):
1342 """
1343 Test result for guest session counts.
1344 """
1345 def __init__(self, fRc = False, cNumSessions = 0):
1346 tdTestResult.__init__(self, fRc = fRc);
1347 self.cNumSessions = cNumSessions;
1348
1349class tdDebugSettings(object):
1350 """
1351 Contains local test debug settings.
1352 """
1353 def __init__(self, sImgPath = None):
1354 self.sImgPath = sImgPath;
1355 self.sVBoxServiceLogPath = '';
1356 self.fNoExit = False;
1357
1358class SubTstDrvAddGuestCtrl(base.SubTestDriverBase):
1359 """
1360 Sub-test driver for executing guest control (VBoxService, IGuest) tests.
1361 """
1362
1363 def __init__(self, oTstDrv):
1364 base.SubTestDriverBase.__init__(self, oTstDrv, 'add-guest-ctrl', 'Guest Control');
1365
1366 ## @todo base.TestBase.
1367 self.asTestsDef = [
1368 'debug',
1369 'session_basic', 'session_env', 'session_file_ref', 'session_dir_ref', 'session_proc_ref', 'session_reboot',
1370 'exec_basic', 'exec_timeout',
1371 'dir_create', 'dir_create_temp', 'dir_read',
1372 'file_open', 'file_remove', 'file_stat', 'file_read', 'file_write',
1373 'copy_to', 'copy_from',
1374 'update_additions'
1375 ];
1376 self.asTests = self.asTestsDef;
1377 self.fSkipKnownBugs = False;
1378 self.oTestFiles = None # type: vboxtestfileset.TestFileSet
1379 self.oDebug = tdDebugSettings();
1380
1381 def parseOption(self, asArgs, iArg): # pylint: disable=too-many-branches,too-many-statements
1382 if asArgs[iArg] == '--add-guest-ctrl-tests':
1383 iArg += 1;
1384 iNext = self.oTstDrv.requireMoreArgs(1, asArgs, iArg);
1385 if asArgs[iArg] == 'all': # Nice for debugging scripts.
1386 self.asTests = self.asTestsDef;
1387 else:
1388 self.asTests = asArgs[iArg].split(':');
1389 for s in self.asTests:
1390 if s not in self.asTestsDef:
1391 raise base.InvalidOption('The "--add-guest-ctrl-tests" value "%s" is not valid; valid values are: %s'
1392 % (s, ' '.join(self.asTestsDef)));
1393 return iNext;
1394 if asArgs[iArg] == '--add-guest-ctrl-skip-known-bugs':
1395 self.fSkipKnownBugs = True;
1396 return iArg + 1;
1397 if asArgs[iArg] == '--no-add-guest-ctrl-skip-known-bugs':
1398 self.fSkipKnownBugs = False;
1399 return iArg + 1;
1400 if asArgs[iArg] == '--add-guest-ctrl-debug-img':
1401 iArg += 1;
1402 iNext = self.oTstDrv.requireMoreArgs(1, asArgs, iArg);
1403 self.oDebug.sImgPath = asArgs[iArg];
1404 return iNext;
1405 if asArgs[iArg] == '--add-guest-ctrl-debug-no-exit':
1406 self.oDebug.fNoExit = True;
1407 return iArg + 1;
1408 return iArg;
1409
1410 def showUsage(self):
1411 base.SubTestDriverBase.showUsage(self);
1412 reporter.log(' --add-guest-ctrl-tests <s1[:s2[:]]>');
1413 reporter.log(' Default: %s (all)' % (':'.join(self.asTestsDef)));
1414 reporter.log(' --add-guest-ctrl-skip-known-bugs');
1415 reporter.log(' Skips known bugs. Default: --no-add-guest-ctrl-skip-known-bugs');
1416 reporter.log('Debugging:');
1417 reporter.log(' --add-guest-ctrl-debug-img');
1418 reporter.log(' Sets VBoxService image to deploy for debugging');
1419 reporter.log(' --add-guest-ctrl-debug-no-exit');
1420 reporter.log(' Does not tear down and exit the test driver after running the tests');
1421 return True;
1422
1423 def testIt(self, oTestVm, oSession, oTxsSession):
1424 """
1425 Executes the test.
1426
1427 Returns fRc, oTxsSession. The latter may have changed.
1428 """
1429 reporter.log("Active tests: %s" % (self.asTests,));
1430
1431 # The tests. Must-succeed tests should be first.
1432 atTests = [
1433 ( True, self.prepareGuestForDebugging, None, 'Manaul Debugging',),
1434 ( True, self.prepareGuestForTesting, None, 'Preparations',),
1435 ( True, self.testGuestCtrlSession, 'session_basic', 'Session Basics',),
1436 ( True, self.testGuestCtrlExec, 'exec_basic', 'Execution',),
1437 ( False, self.testGuestCtrlExecTimeout, 'exec_timeout', 'Execution Timeouts',),
1438 ( False, self.testGuestCtrlSessionEnvironment, 'session_env', 'Session Environment',),
1439 ( False, self.testGuestCtrlSessionFileRefs, 'session_file_ref', 'Session File References',),
1440 #( False, self.testGuestCtrlSessionDirRefs, 'session_dir_ref', 'Session Directory References',),
1441 ( False, self.testGuestCtrlSessionProcRefs, 'session_proc_ref', 'Session Process References',),
1442 ( False, self.testGuestCtrlDirCreate, 'dir_create', 'Creating directories',),
1443 ( False, self.testGuestCtrlDirCreateTemp, 'dir_create_temp', 'Creating temporary directories',),
1444 ( False, self.testGuestCtrlDirRead, 'dir_read', 'Reading directories',),
1445 ( False, self.testGuestCtrlCopyTo, 'copy_to', 'Copy to guest',),
1446 ( False, self.testGuestCtrlCopyFrom, 'copy_from', 'Copy from guest',),
1447 ( False, self.testGuestCtrlFileStat, 'file_stat', 'Querying file information (stat)',),
1448 ( False, self.testGuestCtrlFileOpen, 'file_open', 'File open',),
1449 ( False, self.testGuestCtrlFileRead, 'file_read', 'File read',),
1450 ( False, self.testGuestCtrlFileWrite, 'file_write', 'File write',),
1451 ( False, self.testGuestCtrlFileRemove, 'file_remove', 'Removing files',), # Destroys prepped files.
1452 ( False, self.testGuestCtrlSessionReboot, 'session_reboot', 'Session w/ Guest Reboot',), # May zap /tmp.
1453 ( False, self.testGuestCtrlUpdateAdditions, 'update_additions', 'Updating Guest Additions',),
1454 ];
1455
1456 fRc = True;
1457 for fMustSucceed, fnHandler, sShortNm, sTestNm in atTests:
1458 reporter.testStart(sTestNm);
1459
1460 if sShortNm is None or sShortNm in self.asTests:
1461 # Returns (fRc, oTxsSession, oSession) - but only the first one is mandatory.
1462 aoResult = fnHandler(oSession, oTxsSession, oTestVm);
1463 if aoResult is None or isinstance(aoResult, bool):
1464 fRcTest = aoResult;
1465 else:
1466 fRcTest = aoResult[0];
1467 if len(aoResult) > 1:
1468 oTxsSession = aoResult[1];
1469 if len(aoResult) > 2:
1470 oSession = aoResult[2];
1471 assert len(aoResult) == 3;
1472 else:
1473 fRcTest = None;
1474
1475 if fRcTest is False and reporter.testErrorCount() == 0:
1476 fRcTest = reporter.error('Buggy test! Returned False w/o logging the error!');
1477 if reporter.testDone(fRcTest is None)[1] != 0:
1478 fRcTest = False;
1479 fRc = False;
1480
1481 # Stop execution if this is a must-succeed test and it failed.
1482 if fRcTest is False and fMustSucceed is True:
1483 reporter.log('Skipping any remaining tests since the previous one failed.');
1484 break;
1485
1486 return (fRc, oTxsSession);
1487
1488 def prepareGuestForDebugging(self, oSession, oTxsSession, oTestVm): # pylint: disable=unused-argument
1489 """
1490 Prepares a guest for (manual) debugging.
1491
1492 This involves copying over and invoking a the locally built VBoxService binary.
1493 """
1494
1495 if self.oDebug.sImgPath is None: # If no debugging enabled, bail out.
1496 return True
1497
1498 reporter.log('Preparing for debugging ...');
1499
1500 try:
1501
1502 self.vboxServiceControl(oTxsSession, oTestVm, fStart = False);
1503
1504 if oTestVm.isLinux():
1505 reporter.log('Uploading %s ...' % self.oDebug.sImgPath);
1506 sFileVBoxServiceHst = self.oDebug.sImgPath;
1507 sFileVBoxServiceGst = "/tmp/VBoxService-txs";
1508 oTxsSession.syncUploadFile(sFileVBoxServiceHst, sFileVBoxServiceGst);
1509 oTxsSession.syncChMod(sFileVBoxServiceGst, 0o755);
1510 reporter.log('Executing VBoxService (in background)...');
1511 oTxsSession.syncExec(sFileVBoxServiceGst, (sFileVBoxServiceGst, "-vvvv", "--only-control", \
1512 "--logfile", "/tmp/VBoxService-txs.log") );
1513 elif oTestVm.isWindows():
1514 reporter.log('Uploading %s ...' % self.oDebug.sImgPath);
1515 sFileVBoxServiceHst = self.oDebug.sImgPath;
1516 sFileVBoxServiceGst = os.path.join(self.oTstDrv.getGuestSystemDir(oTestVm), 'VBoxService.exe');
1517 oTxsSession.syncUploadFile(sFileVBoxServiceHst, sFileVBoxServiceGst);
1518 sPathSC = os.path.join(self.oTstDrv.getGuestSystemDir(oTestVm), 'sc.exe');
1519 oTxsSession.syncExec(sPathSC, (sPathSC, "stop", "VBoxService") );
1520 time.sleep(5);
1521 oTxsSession.syncExec(sPathSC, (sPathSC, "start", "VBoxService") );
1522
1523 else: ## @todo Implement others.
1524 reporter.log('Debugging not available on this guest OS yet, skipping ...');
1525
1526 self.vboxServiceControl(oTxsSession, oTestVm, fStart = True);
1527
1528 except:
1529 return reporter.errorXcpt('Unable to prepare for debugging');
1530
1531 return True;
1532
1533 #
1534 # VBoxService handling.
1535 #
1536 def vboxServiceControl(self, oTxsSession, oTestVm, fStart):
1537 """
1538 Controls VBoxService on the guest by starting or stopping the service.
1539 Returns success indicator.
1540 """
1541
1542 fRc = True;
1543
1544 if oTestVm.isWindows():
1545 sPathSC = os.path.join(self.oTstDrv.getGuestSystemDir(oTestVm), 'sc.exe');
1546 if fStart is True:
1547 fRc = self.oTstDrv.txsRunTest(oTxsSession, 'Starting VBoxService with verbose logging', 30 * 1000, \
1548 sPathSC, (sPathSC, 'start', 'VBoxService'));
1549 else:
1550 fRc = self.oTstDrv.txsRunTest(oTxsSession, 'Stopping VBoxService', 30 * 1000, \
1551 sPathSC, (sPathSC, 'stop', 'VBoxService'));
1552 else:
1553 reporter.log('Controlling VBoxService not supported for this guest yet');
1554
1555 return fRc;
1556
1557 def waitForGuestFacility(self, oSession, eFacilityType, sDesc,
1558 eFacilityStatus, cMsTimeout = 30 * 1000):
1559 """
1560 Waits for a guest facility to enter a certain status.
1561 By default the "Active" status is being used.
1562
1563 Returns success status.
1564 """
1565
1566 reporter.log('Waiting for Guest Additions facility "%s" to change to status %s (%dms timeout)...'
1567 % (sDesc, str(eFacilityStatus), cMsTimeout));
1568
1569 fRc = False;
1570
1571 eStatusOld = None;
1572 tsStart = base.timestampMilli();
1573 while base.timestampMilli() - tsStart < cMsTimeout:
1574 try:
1575 eStatus, _ = oSession.o.console.guest.getFacilityStatus(eFacilityType);
1576 reporter.log('Current status is %s' % (str(eStatus)));
1577 if eStatusOld is None:
1578 eStatusOld = eStatus;
1579 except:
1580 reporter.errorXcpt('Getting facility status failed');
1581 break;
1582 if eStatus != eStatusOld:
1583 reporter.log('Status changed to %s' % (str(eStatus)));
1584 eStatusOld = eStatus;
1585 if eStatus == eFacilityStatus:
1586 fRc = True;
1587 break;
1588 self.oTstDrv.sleep(5); # Do some busy waiting.
1589
1590 if not fRc:
1591 reporter.error('Waiting for Guest Additions facility "%s" timed out' % (sDesc));
1592 else:
1593 reporter.log('Guest Additions facility "%s" reached requested status %s after %dms'
1594 % (sDesc, str(eFacilityStatus), base.timestampMilli() - tsStart));
1595
1596 return fRc;
1597
1598 #
1599 # Guest test files.
1600 #
1601
1602 def prepareGuestForTesting(self, oSession, oTxsSession, oTestVm):
1603 """
1604 Prepares the VM for testing, uploading a bunch of files and stuff via TXS.
1605 Returns success indicator.
1606 """
1607 _ = oSession;
1608
1609 #
1610 # Wait for VBoxService to come up.
1611 #
1612 reporter.testStart('Waiting for VBoxService to get started');
1613 fRc = self.waitForGuestFacility(oSession, vboxcon.AdditionsFacilityType_VBoxService, "VBoxService",
1614 vboxcon.AdditionsFacilityStatus_Active);
1615 reporter.testDone();
1616 if not fRc:
1617 return (False, oTxsSession);
1618
1619 #
1620 # Make sure the temporary directory exists.
1621 #
1622 for sDir in [self.oTstDrv.getGuestTempDir(oTestVm), ]:
1623 if oTxsSession.syncMkDirPath(sDir, 0o777) is not True:
1624 return reporter.error('Failed to create directory "%s"!' % (sDir,));
1625
1626 #
1627 # Enable VBoxService verbose logging.
1628 #
1629 self.oDebug.sVBoxServiceLogPath = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), "VBoxService");
1630 if oTxsSession.syncMkDirPath(self.oDebug.sVBoxServiceLogPath, 0o777) is not True:
1631 return reporter.error('Failed to create directory "%s"!' % (self.oDebug.sVBoxServiceLogPath,));
1632 sPathLogFile = oTestVm.pathJoin(self.oDebug.sVBoxServiceLogPath, 'VBoxService.log');
1633
1634 reporter.log('VBoxService logs will be stored in "%s"' % (self.oDebug.sVBoxServiceLogPath,));
1635
1636 if oTestVm.isWindows():
1637 sPathRegExe = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'reg.exe');
1638 sPathVBoxServiceExe = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'VBoxService.exe');
1639 sImagePath = '%s -vvvv --logfile %s' % (sPathVBoxServiceExe, sPathLogFile);
1640 self.oTstDrv.txsRunTest(oTxsSession, 'Enabling VBoxService verbose logging (via registry)', 30 * 1000,
1641 sPathRegExe,
1642 (sPathRegExe, 'add',
1643 '"HKLM\\SYSTEM\\CurrentControlSet\\Services\\VBoxService"',
1644 '/v', 'ImagePath', '/t', 'REG_SZ', '/d', sImagePath, '/f'));
1645
1646 self.vboxServiceControl(oTxsSession, oTestVm, fStart = False);
1647 time.sleep(5);
1648 self.vboxServiceControl(oTxsSession, oTestVm, fStart = True);
1649
1650 else:
1651 reporter.log('Verbose logging for VBoxService not supported for this guest yet');
1652
1653 #
1654 # Generate and upload some random files and dirs to the guest.
1655 # Note! Make sure we don't run into too-long-path issues when using
1656 # the test files on the host if.
1657 #
1658 cchGst = len(self.oTstDrv.getGuestTempDir(oTestVm)) + 1 + len('addgst-1') + 1;
1659 cchHst = len(self.oTstDrv.sScratchPath) + 1 + len('copyto/addgst-1') + 1;
1660 cchMaxPath = 230;
1661 if cchHst > cchGst:
1662 cchMaxPath -= cchHst - cchGst;
1663 reporter.log('cchMaxPath=%s (cchHst=%s, cchGst=%s)' % (cchMaxPath, cchHst, cchGst,));
1664 asCompatibleWith = None;
1665 if oTestVm.isWindows():
1666 asCompatibleWith = [ 'win' ];
1667 self.oTestFiles = vboxtestfileset.TestFileSet(oTestVm,
1668 self.oTstDrv.getGuestTempDir(oTestVm), 'addgst-1',
1669 cchMaxPath = cchMaxPath, asCompatibleWith = asCompatibleWith);
1670 return self.oTestFiles.upload(oTxsSession, self.oTstDrv);
1671
1672
1673 #
1674 # gctrlXxxx stuff.
1675 #
1676
1677 def gctrlCopyFileFrom(self, oGuestSession, oTest, fExpected):
1678 """
1679 Helper function to copy a single file from the guest to the host.
1680 """
1681 #
1682 # Do the copying.
1683 #
1684 reporter.log2('Copying guest file "%s" to host "%s"' % (limitString(oTest.sSrc), limitString(oTest.sDst)));
1685 try:
1686 if self.oTstDrv.fpApiVer >= 5.0:
1687 oCurProgress = oGuestSession.fileCopyFromGuest(oTest.sSrc, oTest.sDst, oTest.afFlags);
1688 else:
1689 oCurProgress = oGuestSession.copyFrom(oTest.sSrc, oTest.sDst, oTest.afFlags);
1690 except:
1691 reporter.maybeErrXcpt(fExpected, 'Copy from exception for sSrc="%s", sDst="%s":' % (oTest.sSrc, oTest.sDst,));
1692 return False;
1693 if oCurProgress is None:
1694 return reporter.error('No progress object returned');
1695 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlFileCopyFrom");
1696 oProgress.wait();
1697 if not oProgress.isSuccess():
1698 oProgress.logResult(fIgnoreErrors = not fExpected);
1699 return False;
1700
1701 #
1702 # Check the result if we can.
1703 #
1704 if oTest.oSrc:
1705 assert isinstance(oTest.oSrc, testfileset.TestFile);
1706 sDst = oTest.sDst;
1707 if os.path.isdir(sDst):
1708 sDst = os.path.join(sDst, oTest.oSrc.sName);
1709 try:
1710 oFile = open(sDst, 'rb');
1711 except:
1712 return reporter.errorXcpt('open(%s) failed during verfication' % (sDst,));
1713 fEqual = oTest.oSrc.equalFile(oFile);
1714 oFile.close();
1715 if not fEqual:
1716 return reporter.error('Content differs for "%s"' % (sDst,));
1717
1718 return True;
1719
1720 def __compareTestDir(self, oDir, sHostPath): # type: (testfileset.TestDir, str) -> bool
1721 """
1722 Recursively compare the content of oDir and sHostPath.
1723
1724 Returns True on success, False + error logging on failure.
1725
1726 Note! This ASSUMES that nothing else was copied to sHostPath!
1727 """
1728 #
1729 # First check out all the entries and files in the directory.
1730 #
1731 dLeftUpper = dict(oDir.dChildrenUpper);
1732 try:
1733 asEntries = os.listdir(sHostPath);
1734 except:
1735 return reporter.errorXcpt('os.listdir(%s) failed' % (sHostPath,));
1736
1737 fRc = True;
1738 for sEntry in asEntries:
1739 sEntryUpper = sEntry.upper();
1740 if sEntryUpper not in dLeftUpper:
1741 fRc = reporter.error('Unexpected entry "%s" in "%s"' % (sEntry, sHostPath,));
1742 else:
1743 oFsObj = dLeftUpper[sEntryUpper];
1744 del dLeftUpper[sEntryUpper];
1745
1746 if isinstance(oFsObj, testfileset.TestFile):
1747 sFilePath = os.path.join(sHostPath, oFsObj.sName);
1748 try:
1749 oFile = open(sFilePath, 'rb');
1750 except:
1751 fRc = reporter.errorXcpt('open(%s) failed during verfication' % (sFilePath,));
1752 else:
1753 fEqual = oFsObj.equalFile(oFile);
1754 oFile.close();
1755 if not fEqual:
1756 fRc = reporter.error('Content differs for "%s"' % (sFilePath,));
1757
1758 # List missing entries:
1759 for sKey in dLeftUpper:
1760 oEntry = dLeftUpper[sKey];
1761 fRc = reporter.error('%s: Missing %s "%s" (src path: %s)'
1762 % (sHostPath, oEntry.sName,
1763 'file' if isinstance(oEntry, testfileset.TestFile) else 'directory', oEntry.sPath));
1764
1765 #
1766 # Recurse into subdirectories.
1767 #
1768 for oFsObj in oDir.aoChildren:
1769 if isinstance(oFsObj, testfileset.TestDir):
1770 fRc = self.__compareTestDir(oFsObj, os.path.join(sHostPath, oFsObj.sName)) and fRc;
1771 return fRc;
1772
1773 def gctrlCopyDirFrom(self, oGuestSession, oTest, fExpected):
1774 """
1775 Helper function to copy a directory from the guest to the host.
1776 """
1777 #
1778 # Do the copying.
1779 #
1780 reporter.log2('Copying guest dir "%s" to host "%s"' % (limitString(oTest.sSrc), limitString(oTest.sDst)));
1781 try:
1782 oCurProgress = oGuestSession.directoryCopyFromGuest(oTest.sSrc, oTest.sDst, oTest.afFlags);
1783 except:
1784 reporter.maybeErrXcpt(fExpected, 'Copy dir from exception for sSrc="%s", sDst="%s":' % (oTest.sSrc, oTest.sDst,));
1785 return False;
1786 if oCurProgress is None:
1787 return reporter.error('No progress object returned');
1788
1789 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlDirCopyFrom");
1790 oProgress.wait();
1791 if not oProgress.isSuccess():
1792 oProgress.logResult(fIgnoreErrors = not fExpected);
1793 return False;
1794
1795 #
1796 # Check the result if we can.
1797 #
1798 if oTest.oSrc:
1799 assert isinstance(oTest.oSrc, testfileset.TestDir);
1800 sDst = oTest.sDst;
1801 if oTest.fIntoDst:
1802 return self.__compareTestDir(oTest.oSrc, os.path.join(sDst, oTest.oSrc.sName));
1803 oDummy = testfileset.TestDir(None, 'dummy');
1804 oDummy.aoChildren = [oTest.oSrc,]
1805 oDummy.dChildrenUpper = { oTest.oSrc.sName.upper(): oTest.oSrc, };
1806 return self.__compareTestDir(oDummy, sDst);
1807 return True;
1808
1809 def gctrlCopyFileTo(self, oGuestSession, sSrc, sDst, afFlags, fIsError):
1810 """
1811 Helper function to copy a single file from the host to the guest.
1812 """
1813 reporter.log2('Copying host file "%s" to guest "%s" (flags %s)' % (limitString(sSrc), limitString(sDst), afFlags));
1814 try:
1815 if self.oTstDrv.fpApiVer >= 5.0:
1816 oCurProgress = oGuestSession.fileCopyToGuest(sSrc, sDst, afFlags);
1817 else:
1818 oCurProgress = oGuestSession.copyTo(sSrc, sDst, afFlags);
1819 except:
1820 reporter.maybeErrXcpt(fIsError, 'sSrc=%s sDst=%s' % (sSrc, sDst,));
1821 return False;
1822
1823 if oCurProgress is None:
1824 return reporter.error('No progress object returned');
1825 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlCopyFileTo");
1826
1827 try:
1828 oProgress.wait();
1829 if not oProgress.isSuccess():
1830 oProgress.logResult(fIgnoreErrors = not fIsError);
1831 return False;
1832 except:
1833 reporter.maybeErrXcpt(fIsError, 'Wait exception for sSrc="%s", sDst="%s":' % (sSrc, sDst));
1834 return False;
1835 return True;
1836
1837 def gctrlCopyDirTo(self, oGuestSession, sSrc, sDst, afFlags, fIsError):
1838 """
1839 Helper function to copy a directory tree from the host to the guest.
1840 """
1841 reporter.log2('Copying host directory "%s" to guest "%s" (flags %s)' % (limitString(sSrc), limitString(sDst), afFlags));
1842 try:
1843 oCurProgress = oGuestSession.directoryCopyToGuest(sSrc, sDst, afFlags);
1844 except:
1845 reporter.maybeErrXcpt(fIsError, 'sSrc=%s sDst=%s' % (sSrc, sDst,));
1846 return False;
1847
1848 if oCurProgress is None:
1849 return reporter.error('No progress object returned');
1850 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlCopyFileTo");
1851
1852 try:
1853 oProgress.wait();
1854 if not oProgress.isSuccess():
1855 oProgress.logResult(fIgnoreErrors = not fIsError);
1856 return False;
1857 except:
1858 reporter.maybeErrXcpt(fIsError, 'Wait exception for sSrc="%s", sDst="%s":' % (sSrc, sDst));
1859 return False;
1860 return True;
1861
1862 def gctrlCreateDir(self, oTest, oRes, oGuestSession):
1863 """
1864 Helper function to create a guest directory specified in the current test.
1865 """
1866 reporter.log2('Creating directory "%s"' % (limitString(oTest.sDirectory),));
1867 try:
1868 oGuestSession.directoryCreate(oTest.sDirectory, oTest.fMode, oTest.afFlags);
1869 except:
1870 reporter.maybeErrXcpt(oRes.fRc, 'Failed to create "%s" fMode=%o afFlags=%s'
1871 % (oTest.sDirectory, oTest.fMode, oTest.afFlags,));
1872 return not oRes.fRc;
1873 if oRes.fRc is not True:
1874 return reporter.error('Did not expect to create directory "%s"!' % (oTest.sDirectory,));
1875
1876 # Check if the directory now exists.
1877 try:
1878 if self.oTstDrv.fpApiVer >= 5.0:
1879 fDirExists = oGuestSession.directoryExists(oTest.sDirectory, False);
1880 else:
1881 fDirExists = oGuestSession.directoryExists(oTest.sDirectory);
1882 except:
1883 return reporter.errorXcpt('directoryExists failed on "%s"!' % (oTest.sDirectory,));
1884 if not fDirExists:
1885 return reporter.errorXcpt('directoryExists returned False on "%s" after directoryCreate succeeded!'
1886 % (oTest.sDirectory,));
1887 return True;
1888
1889 def gctrlReadDirTree(self, oTest, oGuestSession, fIsError, sSubDir = None):
1890 """
1891 Helper function to recursively read a guest directory tree specified in the current test.
1892 """
1893 sDir = oTest.sDirectory;
1894 sFilter = oTest.sFilter;
1895 afFlags = oTest.afFlags;
1896 oTestVm = oTest.oCreds.oTestVm;
1897 sCurDir = oTestVm.pathJoin(sDir, sSubDir) if sSubDir else sDir;
1898
1899 fRc = True; # Be optimistic.
1900 cDirs = 0; # Number of directories read.
1901 cFiles = 0; # Number of files read.
1902 cOthers = 0; # Other files.
1903
1904 # Open the directory:
1905 reporter.log2('Directory="%s", filter="%s", afFlags="%s"' % (limitString(sCurDir), sFilter, afFlags));
1906 try:
1907 oCurDir = oGuestSession.directoryOpen(sCurDir, sFilter, afFlags);
1908 except:
1909 reporter.maybeErrXcpt(fIsError, 'sCurDir=%s sFilter=%s afFlags=%s' % (sCurDir, sFilter, afFlags,))
1910 return (False, 0, 0, 0);
1911
1912 # Read the directory.
1913 while fRc is True:
1914 try:
1915 oFsObjInfo = oCurDir.read();
1916 except Exception as oXcpt:
1917 if vbox.ComError.notEqual(oXcpt, vbox.ComError.VBOX_E_OBJECT_NOT_FOUND):
1918 if self.oTstDrv.fpApiVer > 5.2:
1919 reporter.errorXcpt('Error reading directory "%s":' % (sCurDir,));
1920 else:
1921 # Unlike fileOpen, directoryOpen will not fail if the directory does not exist.
1922 reporter.maybeErrXcpt(fIsError, 'Error reading directory "%s":' % (sCurDir,));
1923 fRc = False;
1924 else:
1925 reporter.log2('\tNo more directory entries for "%s"' % (limitString(sCurDir),));
1926 break;
1927
1928 try:
1929 sName = oFsObjInfo.name;
1930 eType = oFsObjInfo.type;
1931 except:
1932 fRc = reporter.errorXcpt();
1933 break;
1934
1935 if sName in ('.', '..', ):
1936 if eType != vboxcon.FsObjType_Directory:
1937 fRc = reporter.error('Wrong type for "%s": %d, expected %d (Directory)'
1938 % (sName, eType, vboxcon.FsObjType_Directory));
1939 elif eType == vboxcon.FsObjType_Directory:
1940 reporter.log2(' Directory "%s"' % limitString(oFsObjInfo.name));
1941 aSubResult = self.gctrlReadDirTree(oTest, oGuestSession, fIsError,
1942 oTestVm.pathJoin(sSubDir, sName) if sSubDir else sName);
1943 fRc = aSubResult[0];
1944 cDirs += aSubResult[1] + 1;
1945 cFiles += aSubResult[2];
1946 cOthers += aSubResult[3];
1947 elif eType is vboxcon.FsObjType_File:
1948 reporter.log4(' File "%s"' % oFsObjInfo.name);
1949 cFiles += 1;
1950 elif eType is vboxcon.FsObjType_Symlink:
1951 reporter.log4(' Symlink "%s" -- not tested yet' % oFsObjInfo.name);
1952 cOthers += 1;
1953 elif oTestVm.isWindows() \
1954 or oTestVm.isOS2() \
1955 or eType not in (vboxcon.FsObjType_Fifo, vboxcon.FsObjType_DevChar, vboxcon.FsObjType_DevBlock,
1956 vboxcon.FsObjType_Socket, vboxcon.FsObjType_WhiteOut):
1957 fRc = reporter.error('Directory "%s" contains invalid directory entry "%s" (type %d)' %
1958 (sCurDir, oFsObjInfo.name, oFsObjInfo.type,));
1959 else:
1960 cOthers += 1;
1961
1962 # Close the directory
1963 try:
1964 oCurDir.close();
1965 except:
1966 fRc = reporter.errorXcpt('sCurDir=%s' % (sCurDir));
1967
1968 return (fRc, cDirs, cFiles, cOthers);
1969
1970 def gctrlReadDirTree2(self, oGuestSession, oDir): # type: (testfileset.TestDir) -> bool
1971 """
1972 Helper function to recursively read a guest directory tree specified in the current test.
1973 """
1974
1975 #
1976 # Process the directory.
1977 #
1978
1979 # Open the directory:
1980 try:
1981 oCurDir = oGuestSession.directoryOpen(oDir.sPath, '', None);
1982 except:
1983 return reporter.errorXcpt('sPath=%s' % (oDir.sPath,));
1984
1985 # Read the directory.
1986 dLeftUpper = dict(oDir.dChildrenUpper);
1987 cDot = 0;
1988 cDotDot = 0;
1989 fRc = True;
1990 while True:
1991 try:
1992 oFsObjInfo = oCurDir.read();
1993 except Exception as oXcpt:
1994 if vbox.ComError.notEqual(oXcpt, vbox.ComError.VBOX_E_OBJECT_NOT_FOUND):
1995 fRc = reporter.errorXcpt('Error reading directory "%s":' % (oDir.sPath,));
1996 break;
1997
1998 try:
1999 sName = oFsObjInfo.name;
2000 eType = oFsObjInfo.type;
2001 cbFile = oFsObjInfo.objectSize;
2002 ## @todo check further attributes.
2003 except:
2004 fRc = reporter.errorXcpt();
2005 break;
2006
2007 # '.' and '..' entries are not present in oDir.aoChildren, so special treatment:
2008 if sName in ('.', '..', ):
2009 if eType != vboxcon.FsObjType_Directory:
2010 fRc = reporter.error('Wrong type for "%s": %d, expected %d (Directory)'
2011 % (sName, eType, vboxcon.FsObjType_Directory));
2012 if sName == '.': cDot += 1;
2013 else: cDotDot += 1;
2014 else:
2015 # Find the child and remove it from the dictionary.
2016 sNameUpper = sName.upper();
2017 oFsObj = dLeftUpper.get(sNameUpper);
2018 if oFsObj is None:
2019 fRc = reporter.error('Unknown object "%s" found in "%s" (type %s, size %s)!'
2020 % (sName, oDir.sPath, eType, cbFile,));
2021 else:
2022 del dLeftUpper[sNameUpper];
2023
2024 # Check type
2025 if isinstance(oFsObj, testfileset.TestDir):
2026 if eType != vboxcon.FsObjType_Directory:
2027 fRc = reporter.error('%s: expected directory (%d), got eType=%d!'
2028 % (oFsObj.sPath, vboxcon.FsObjType_Directory, eType,));
2029 elif isinstance(oFsObj, testfileset.TestFile):
2030 if eType != vboxcon.FsObjType_File:
2031 fRc = reporter.error('%s: expected file (%d), got eType=%d!'
2032 % (oFsObj.sPath, vboxcon.FsObjType_File, eType,));
2033 else:
2034 fRc = reporter.error('%s: WTF? type=%s' % (oFsObj.sPath, type(oFsObj),));
2035
2036 # Check the name.
2037 if oFsObj.sName != sName:
2038 fRc = reporter.error('%s: expected name "%s", got "%s" instead!' % (oFsObj.sPath, oFsObj.sName, sName,));
2039
2040 # Check the size if a file.
2041 if isinstance(oFsObj, testfileset.TestFile) and cbFile != oFsObj.cbContent:
2042 fRc = reporter.error('%s: expected size %s, got %s instead!' % (oFsObj.sPath, oFsObj.cbContent, cbFile,));
2043
2044 ## @todo check timestamps and attributes.
2045
2046 # Close the directory
2047 try:
2048 oCurDir.close();
2049 except:
2050 fRc = reporter.errorXcpt('oDir.sPath=%s' % (oDir.sPath,));
2051
2052 # Any files left over?
2053 for sKey in dLeftUpper:
2054 oFsObj = dLeftUpper[sKey];
2055 fRc = reporter.error('%s: Was not returned! (%s)' % (oFsObj.sPath, type(oFsObj),));
2056
2057 # Check the dot and dot-dot counts.
2058 if cDot != 1:
2059 fRc = reporter.error('%s: Found %s "." entries, expected exactly 1!' % (oDir.sPath, cDot,));
2060 if cDotDot != 1:
2061 fRc = reporter.error('%s: Found %s ".." entries, expected exactly 1!' % (oDir.sPath, cDotDot,));
2062
2063 #
2064 # Recurse into subdirectories using info from oDir.
2065 #
2066 for oFsObj in oDir.aoChildren:
2067 if isinstance(oFsObj, testfileset.TestDir):
2068 fRc = self.gctrlReadDirTree2(oGuestSession, oFsObj) and fRc;
2069
2070 return fRc;
2071
2072 def gctrlExecDoTest(self, i, oTest, oRes, oGuestSession):
2073 """
2074 Wrapper function around gctrlExecute to provide more sanity checking
2075 when needed in actual execution tests.
2076 """
2077 reporter.log('Testing #%d, cmd="%s" ...' % (i, oTest.sCmd));
2078 fRcExec = self.gctrlExecute(oTest, oGuestSession, oRes.fRc);
2079 if fRcExec == oRes.fRc:
2080 fRc = True;
2081 if fRcExec is True:
2082 # Compare exit status / code on successful process execution.
2083 if oTest.uExitStatus != oRes.uExitStatus \
2084 or oTest.iExitCode != oRes.iExitCode:
2085 fRc = reporter.error('Test #%d (%s) failed: Got exit status + code %d,%d, expected %d,%d'
2086 % (i, oTest.asArgs, oTest.uExitStatus, oTest.iExitCode,
2087 oRes.uExitStatus, oRes.iExitCode));
2088
2089 # Compare test / result buffers on successful process execution.
2090 if oTest.sBuf is not None and oRes.sBuf is not None:
2091 if not utils.areBytesEqual(oTest.sBuf, oRes.sBuf):
2092 fRc = reporter.error('Test #%d (%s) failed: Got buffer\n%s (%d bytes), expected\n%s (%d bytes)'
2093 % (i, oTest.asArgs,
2094 map(hex, map(ord, oTest.sBuf)), len(oTest.sBuf),
2095 map(hex, map(ord, oRes.sBuf)), len(oRes.sBuf)));
2096 reporter.log2('Test #%d passed: Buffers match (%d bytes)' % (i, len(oRes.sBuf)));
2097 elif oRes.sBuf and not oTest.sBuf:
2098 fRc = reporter.error('Test #%d (%s) failed: Got no buffer data, expected\n%s (%dbytes)' %
2099 (i, oTest.asArgs, map(hex, map(ord, oRes.sBuf)), len(oRes.sBuf),));
2100
2101 if oRes.cbStdOut is not None and oRes.cbStdOut != oTest.cbStdOut:
2102 fRc = reporter.error('Test #%d (%s) failed: Got %d bytes of stdout data, expected %d'
2103 % (i, oTest.asArgs, oTest.cbStdOut, oRes.cbStdOut));
2104 if oRes.cbStdErr is not None and oRes.cbStdErr != oTest.cbStdErr:
2105 fRc = reporter.error('Test #%d (%s) failed: Got %d bytes of stderr data, expected %d'
2106 % (i, oTest.asArgs, oTest.cbStdErr, oRes.cbStdErr));
2107 else:
2108 fRc = reporter.error('Test #%d (%s) failed: Got %s, expected %s' % (i, oTest.asArgs, fRcExec, oRes.fRc));
2109 return fRc;
2110
2111 def gctrlExecute(self, oTest, oGuestSession, fIsError): # pylint: disable=too-many-statements
2112 """
2113 Helper function to execute a program on a guest, specified in the current test.
2114
2115 Note! This weirdo returns results (process exitcode and status) in oTest.
2116 """
2117 fRc = True; # Be optimistic.
2118
2119 # Reset the weird result stuff:
2120 oTest.cbStdOut = 0;
2121 oTest.cbStdErr = 0;
2122 oTest.sBuf = '';
2123 oTest.uExitStatus = 0;
2124 oTest.iExitCode = 0;
2125
2126 ## @todo Compare execution timeouts!
2127 #tsStart = base.timestampMilli();
2128
2129 try:
2130 reporter.log2('Using session user=%s, sDomain=%s, name=%s, timeout=%d'
2131 % (oGuestSession.user, oGuestSession.domain, oGuestSession.name, oGuestSession.timeout,));
2132 except:
2133 return reporter.errorXcpt();
2134
2135 #
2136 # Start the process:
2137 #
2138 reporter.log2('Executing sCmd=%s, afFlags=%s, timeoutMS=%d, asArgs=%s, asEnv=%s'
2139 % (oTest.sCmd, oTest.afFlags, oTest.timeoutMS, limitString(oTest.asArgs), limitString(oTest.aEnv),));
2140 try:
2141 oProcess = oGuestSession.processCreate(oTest.sCmd,
2142 oTest.asArgs if self.oTstDrv.fpApiVer >= 5.0 else oTest.asArgs[1:],
2143 oTest.aEnv, oTest.afFlags, oTest.timeoutMS);
2144 except:
2145 reporter.maybeErrXcpt(fIsError, 'asArgs=%s' % (oTest.asArgs,));
2146 return False;
2147 if oProcess is None:
2148 return reporter.error('oProcess is None! (%s)' % (oTest.asArgs,));
2149
2150 #time.sleep(5); # try this if you want to see races here.
2151
2152 # Wait for the process to start properly:
2153 reporter.log2('Process start requested, waiting for start (%dms) ...' % (oTest.timeoutMS,));
2154 iPid = -1;
2155 aeWaitFor = [ vboxcon.ProcessWaitForFlag_Start, ];
2156 try:
2157 eWaitResult = oProcess.waitForArray(aeWaitFor, oTest.timeoutMS);
2158 except:
2159 reporter.maybeErrXcpt(fIsError, 'waitforArray failed for asArgs=%s' % (oTest.asArgs,));
2160 fRc = False;
2161 else:
2162 try:
2163 eStatus = oProcess.status;
2164 iPid = oProcess.PID;
2165 except:
2166 fRc = reporter.errorXcpt('asArgs=%s' % (oTest.asArgs,));
2167 else:
2168 reporter.log2('Wait result returned: %d, current process status is: %d' % (eWaitResult, eStatus,));
2169
2170 #
2171 # Wait for the process to run to completion if necessary.
2172 #
2173 # Note! The above eWaitResult return value can be ignored as it will
2174 # (mostly) reflect the process status anyway.
2175 #
2176 if eStatus == vboxcon.ProcessStatus_Started:
2177
2178 # What to wait for:
2179 aeWaitFor = [ vboxcon.ProcessWaitForFlag_Terminate, ];
2180 if vboxcon.ProcessCreateFlag_WaitForStdOut in oTest.afFlags:
2181 aeWaitFor.append(vboxcon.ProcessWaitForFlag_StdOut);
2182 if vboxcon.ProcessCreateFlag_WaitForStdErr in oTest.afFlags:
2183 aeWaitFor.append(vboxcon.ProcessWaitForFlag_StdErr);
2184 ## @todo Add vboxcon.ProcessWaitForFlag_StdIn.
2185
2186 reporter.log2('Process (PID %d) started, waiting for termination (%dms), aeWaitFor=%s ...'
2187 % (iPid, oTest.timeoutMS, aeWaitFor));
2188 acbFdOut = [0,0,0];
2189 while True:
2190 try:
2191 eWaitResult = oProcess.waitForArray(aeWaitFor, oTest.timeoutMS);
2192 except KeyboardInterrupt: # Not sure how helpful this is, but whatever.
2193 reporter.error('Process (PID %d) execution interrupted' % (iPid,));
2194 try: oProcess.close();
2195 except: pass;
2196 break;
2197 except:
2198 fRc = reporter.errorXcpt('asArgs=%s' % (oTest.asArgs,));
2199 break;
2200 #reporter.log2('Wait returned: %d' % (eWaitResult,));
2201
2202 # Process output:
2203 for eFdResult, iFd, sFdNm in [ (vboxcon.ProcessWaitResult_StdOut, 1, 'stdout'),
2204 (vboxcon.ProcessWaitResult_StdErr, 2, 'stderr'), ]:
2205 if eWaitResult in (eFdResult, vboxcon.ProcessWaitResult_WaitFlagNotSupported):
2206 try:
2207 abBuf = oProcess.read(iFd, 64 * 1024, oTest.timeoutMS);
2208 except KeyboardInterrupt: # Not sure how helpful this is, but whatever.
2209 reporter.error('Process (PID %d) execution interrupted' % (iPid,));
2210 try: oProcess.close();
2211 except: pass;
2212 except:
2213 reporter.maybeErrXcpt(fIsError, 'asArgs=%s' % (oTest.asArgs,));
2214 else:
2215 if abBuf:
2216 reporter.log2('Process (PID %d) got %d bytes of %s data (type: %s)'
2217 % (iPid, len(abBuf), sFdNm, type(abBuf)));
2218 if reporter.getVerbosity() >= 4:
2219 sBuf = '';
2220 if sys.version_info >= (2, 7):
2221 if isinstance(abBuf, memoryview): ## @todo Why is this happening?
2222 abBuf = abBuf.tobytes();
2223 sBuf = abBuf.decode("utf-8");
2224 if isinstance(abBuf, buffer):
2225 sBuf = str(abBuf);
2226 for sLine in sBuf.splitlines():
2227 reporter.log4('%s: %s' % (sFdNm, sLine));
2228 acbFdOut[iFd] += len(abBuf);
2229 oTest.sBuf = abBuf; ## @todo Figure out how to uniform + append!
2230
2231 ## Process input (todo):
2232 #if eWaitResult in (vboxcon.ProcessWaitResult_StdIn, vboxcon.ProcessWaitResult_WaitFlagNotSupported):
2233 # reporter.log2('Process (PID %d) needs stdin data' % (iPid,));
2234
2235 # Termination or error?
2236 if eWaitResult in (vboxcon.ProcessWaitResult_Terminate,
2237 vboxcon.ProcessWaitResult_Error,
2238 vboxcon.ProcessWaitResult_Timeout,):
2239 try: eStatus = oProcess.status;
2240 except: fRc = reporter.errorXcpt('asArgs=%s' % (oTest.asArgs,));
2241 reporter.log2('Process (PID %d) reported terminate/error/timeout: %d, status: %d'
2242 % (iPid, eWaitResult, eStatus,));
2243 break;
2244
2245 # End of the wait loop.
2246 _, oTest.cbStdOut, oTest.cbStdErr = acbFdOut;
2247
2248 try: eStatus = oProcess.status;
2249 except: fRc = reporter.errorXcpt('asArgs=%s' % (oTest.asArgs,));
2250 reporter.log2('Final process status (PID %d) is: %d' % (iPid, eStatus));
2251 reporter.log2('Process (PID %d) %d stdout, %d stderr' % (iPid, oTest.cbStdOut, oTest.cbStdErr));
2252
2253 #
2254 # Get the final status and exit code of the process.
2255 #
2256 try:
2257 oTest.uExitStatus = oProcess.status;
2258 oTest.iExitCode = oProcess.exitCode;
2259 except:
2260 fRc = reporter.errorXcpt('asArgs=%s' % (oTest.asArgs,));
2261 reporter.log2('Process (PID %d) has exit code: %d; status: %d ' % (iPid, oTest.iExitCode, oTest.uExitStatus));
2262 return fRc;
2263
2264 def testGuestCtrlSessionEnvironment(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
2265 """
2266 Tests the guest session environment changes.
2267 """
2268 aoTests = [
2269 # Check basic operations.
2270 tdTestSessionEx([ # Initial environment is empty.
2271 tdStepSessionCheckEnv(),
2272 # Check clearing empty env.
2273 tdStepSessionClearEnv(),
2274 tdStepSessionCheckEnv(),
2275 # Check set.
2276 tdStepSessionSetEnv('FOO', 'BAR'),
2277 tdStepSessionCheckEnv(['FOO=BAR',]),
2278 tdStepRequireMinimumApiVer(5.0), # 4.3 can't cope with the remainder.
2279 tdStepSessionClearEnv(),
2280 tdStepSessionCheckEnv(),
2281 # Check unset.
2282 tdStepSessionUnsetEnv('BAR'),
2283 tdStepSessionCheckEnv(['BAR']),
2284 tdStepSessionClearEnv(),
2285 tdStepSessionCheckEnv(),
2286 # Set + unset.
2287 tdStepSessionSetEnv('FOO', 'BAR'),
2288 tdStepSessionCheckEnv(['FOO=BAR',]),
2289 tdStepSessionUnsetEnv('FOO'),
2290 tdStepSessionCheckEnv(['FOO']),
2291 # Bulk environment changes (via attrib) (shall replace existing 'FOO').
2292 tdStepSessionBulkEnv( ['PATH=/bin:/usr/bin', 'TMPDIR=/var/tmp', 'USER=root']),
2293 tdStepSessionCheckEnv(['PATH=/bin:/usr/bin', 'TMPDIR=/var/tmp', 'USER=root']),
2294 ]),
2295 tdTestSessionEx([ # Check that setting the same value several times works.
2296 tdStepSessionSetEnv('FOO','BAR'),
2297 tdStepSessionCheckEnv([ 'FOO=BAR',]),
2298 tdStepSessionSetEnv('FOO','BAR2'),
2299 tdStepSessionCheckEnv([ 'FOO=BAR2',]),
2300 tdStepSessionSetEnv('FOO','BAR3'),
2301 tdStepSessionCheckEnv([ 'FOO=BAR3',]),
2302 tdStepRequireMinimumApiVer(5.0), # 4.3 can't cope with the remainder.
2303 # Add a little unsetting to the mix.
2304 tdStepSessionSetEnv('BAR', 'BEAR'),
2305 tdStepSessionCheckEnv([ 'FOO=BAR3', 'BAR=BEAR',]),
2306 tdStepSessionUnsetEnv('FOO'),
2307 tdStepSessionCheckEnv([ 'FOO', 'BAR=BEAR',]),
2308 tdStepSessionSetEnv('FOO','BAR4'),
2309 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR',]),
2310 # The environment is case sensitive.
2311 tdStepSessionSetEnv('foo','BAR5'),
2312 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR', 'foo=BAR5']),
2313 tdStepSessionUnsetEnv('foo'),
2314 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR', 'foo']),
2315 ]),
2316 tdTestSessionEx([ # Bulk settings merges stuff, last entry standing.
2317 tdStepSessionBulkEnv(['FOO=bar', 'foo=bar', 'FOO=doofus', 'TMPDIR=/tmp', 'foo=bar2']),
2318 tdStepSessionCheckEnv(['FOO=doofus', 'TMPDIR=/tmp', 'foo=bar2']),
2319 tdStepRequireMinimumApiVer(5.0), # 4.3 is buggy!
2320 tdStepSessionBulkEnv(['2=1+1', 'FOO=doofus2', ]),
2321 tdStepSessionCheckEnv(['2=1+1', 'FOO=doofus2' ]),
2322 ]),
2323 # Invalid variable names.
2324 tdTestSessionEx([
2325 tdStepSessionSetEnv('', 'FOO', vbox.ComError.E_INVALIDARG),
2326 tdStepSessionCheckEnv(),
2327 tdStepRequireMinimumApiVer(5.0), # 4.3 is too relaxed checking input!
2328 tdStepSessionBulkEnv(['', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2329 tdStepSessionCheckEnv(),
2330 tdStepSessionSetEnv('FOO=', 'BAR', vbox.ComError.E_INVALIDARG),
2331 tdStepSessionCheckEnv(),
2332 ]),
2333 # A bit more weird keys/values.
2334 tdTestSessionEx([ tdStepSessionSetEnv('$$$', ''),
2335 tdStepSessionCheckEnv([ '$$$=',]), ]),
2336 tdTestSessionEx([ tdStepSessionSetEnv('$$$', '%%%'),
2337 tdStepSessionCheckEnv([ '$$$=%%%',]),
2338 ]),
2339 tdTestSessionEx([ tdStepRequireMinimumApiVer(5.0), # 4.3 is buggy!
2340 tdStepSessionSetEnv(u'ß$%ß&', ''),
2341 tdStepSessionCheckEnv([ u'ß$%ß&=',]),
2342 ]),
2343 # Misc stuff.
2344 tdTestSessionEx([ tdStepSessionSetEnv('FOO', ''),
2345 tdStepSessionCheckEnv(['FOO=',]),
2346 ]),
2347 tdTestSessionEx([ tdStepSessionSetEnv('FOO', 'BAR'),
2348 tdStepSessionCheckEnv(['FOO=BAR',])
2349 ],),
2350 tdTestSessionEx([ tdStepSessionSetEnv('FOO', 'BAR'),
2351 tdStepSessionSetEnv('BAR', 'BAZ'),
2352 tdStepSessionCheckEnv([ 'FOO=BAR', 'BAR=BAZ',]),
2353 ]),
2354 ];
2355 # Leading '=' in the name is okay for windows guests in 6.1 and later (for driver letter CWDs).
2356 if (self.oTstDrv.fpApiVer < 6.1 and self.oTstDrv.fpApiVer >= 5.0) or not oTestVm.isWindows():
2357 aoTests.append(tdTestSessionEx([tdStepSessionSetEnv('=', '===', vbox.ComError.E_INVALIDARG),
2358 tdStepSessionCheckEnv(),
2359 tdStepSessionSetEnv('=FOO', 'BAR', vbox.ComError.E_INVALIDARG),
2360 tdStepSessionCheckEnv(),
2361 tdStepSessionBulkEnv(['=', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2362 tdStepSessionCheckEnv(),
2363 tdStepSessionBulkEnv(['=FOO', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2364 tdStepSessionCheckEnv(),
2365 tdStepSessionBulkEnv(['=D:=D:/tmp', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2366 tdStepSessionCheckEnv(),
2367 tdStepSessionSetEnv('=D:', 'D:/temp', vbox.ComError.E_INVALIDARG),
2368 tdStepSessionCheckEnv(),
2369 ]));
2370 elif self.oTstDrv.fpApiVer >= 6.1 and oTestVm.isWindows():
2371 aoTests.append(tdTestSessionEx([tdStepSessionSetEnv('=D:', 'D:/tmp'),
2372 tdStepSessionCheckEnv(['=D:=D:/tmp',]),
2373 tdStepSessionBulkEnv(['=D:=D:/temp', '=FOO', 'foo=bar']),
2374 tdStepSessionCheckEnv(['=D:=D:/temp', '=FOO', 'foo=bar']),
2375 tdStepSessionUnsetEnv('=D:'),
2376 tdStepSessionCheckEnv(['=D:', '=FOO', 'foo=bar']),
2377 ]));
2378
2379 return tdTestSessionEx.executeListTestSessions(aoTests, self.oTstDrv, oSession, oTxsSession, oTestVm, 'SessionEnv');
2380
2381 def testGuestCtrlSession(self, oSession, oTxsSession, oTestVm):
2382 """
2383 Tests the guest session handling.
2384 """
2385
2386 #
2387 # Tests:
2388 #
2389 atTests = [
2390 # Invalid parameters.
2391 [ tdTestSession(sUser = ''), tdTestResultSession() ],
2392 # User account without a passwort - forbidden.
2393 [ tdTestSession(sPassword = "" ), tdTestResultSession() ],
2394 # Various wrong credentials.
2395 # Note! Only windows cares about sDomain, the other guests ignores it.
2396 # Note! On Guest Additions < 4.3 this always succeeds because these don't
2397 # support creating dedicated sessions. Instead, guest process creation
2398 # then will fail. See note below.
2399 [ tdTestSession(sPassword = 'bar'), tdTestResultSession() ],
2400 [ tdTestSession(sUser = 'foo', sPassword = 'bar'), tdTestResultSession() ],
2401 [ tdTestSession(sPassword = 'bar', sDomain = 'boo'), tdTestResultSession() ],
2402 [ tdTestSession(sUser = 'foo', sPassword = 'bar', sDomain = 'boo'), tdTestResultSession() ],
2403 ];
2404 if oTestVm.isWindows(): # domain is ignored elsewhere.
2405 atTests.append([ tdTestSession(sDomain = 'boo'), tdTestResultSession() ]);
2406
2407 # Finally, correct credentials.
2408 atTests.append([ tdTestSession(), tdTestResultSession(fRc = True, cNumSessions = 1) ]);
2409
2410 #
2411 # Run the tests.
2412 #
2413 fRc = True;
2414 for (i, tTest) in enumerate(atTests):
2415 oCurTest = tTest[0] # type: tdTestSession
2416 oCurRes = tTest[1] # type: tdTestResult
2417
2418 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
2419 reporter.log('Testing #%d, user="%s", sPassword="%s", sDomain="%s" ...'
2420 % (i, oCurTest.oCreds.sUser, oCurTest.oCreds.sPassword, oCurTest.oCreds.sDomain));
2421 sCurGuestSessionName = 'testGuestCtrlSession: Test #%d' % (i,);
2422 fRc2, oCurGuestSession = oCurTest.createSession(sCurGuestSessionName, fIsError = oCurRes.fRc);
2423
2424 # See note about < 4.3 Guest Additions above.
2425 uProtocolVersion = 2;
2426 if oCurGuestSession is not None:
2427 try:
2428 uProtocolVersion = oCurGuestSession.protocolVersion;
2429 except:
2430 fRc = reporter.errorXcpt('Test #%d' % (i,));
2431
2432 if uProtocolVersion >= 2 and fRc2 is not oCurRes.fRc:
2433 fRc = reporter.error('Test #%d failed: Session creation failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc,));
2434
2435 if fRc2 and oCurGuestSession is None:
2436 fRc = reporter.error('Test #%d failed: no session object' % (i,));
2437 fRc2 = False;
2438
2439 if fRc2:
2440 if uProtocolVersion >= 2: # For Guest Additions < 4.3 getSessionCount() always will return 1.
2441 cCurSessions = oCurTest.getSessionCount(self.oTstDrv.oVBoxMgr);
2442 if cCurSessions != oCurRes.cNumSessions:
2443 fRc = reporter.error('Test #%d failed: Session count does not match: Got %d, expected %d'
2444 % (i, cCurSessions, oCurRes.cNumSessions));
2445 try:
2446 sObjName = oCurGuestSession.name;
2447 except:
2448 fRc = reporter.errorXcpt('Test #%d' % (i,));
2449 else:
2450 if sObjName != sCurGuestSessionName:
2451 fRc = reporter.error('Test #%d failed: Session name does not match: Got "%s", expected "%s"'
2452 % (i, sObjName, sCurGuestSessionName));
2453 fRc2 = oCurTest.closeSession();
2454 if fRc2 is False:
2455 fRc = reporter.error('Test #%d failed: Session could not be closed' % (i,));
2456
2457 if fRc is False:
2458 return (False, oTxsSession);
2459
2460 #
2461 # Multiple sessions.
2462 #
2463 cMaxGuestSessions = 31; # Maximum number of concurrent guest session allowed.
2464 # Actually, this is 32, but we don't test session 0.
2465 aoMultiSessions = {};
2466 reporter.log2('Opening multiple guest tsessions at once ...');
2467 for i in xrange(cMaxGuestSessions + 1):
2468 aoMultiSessions[i] = tdTestSession(sSessionName = 'MultiSession #%d' % (i,));
2469 aoMultiSessions[i].setEnvironment(oSession, oTxsSession, oTestVm);
2470
2471 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr);
2472 reporter.log2('MultiSession test #%d count is %d' % (i, cCurSessions));
2473 if cCurSessions != i:
2474 return (reporter.error('MultiSession count is %d, expected %d' % (cCurSessions, i)), oTxsSession);
2475 fRc2, _ = aoMultiSessions[i].createSession('MultiSession #%d' % (i,), i < cMaxGuestSessions);
2476 if fRc2 is not True:
2477 if i < cMaxGuestSessions:
2478 return (reporter.error('MultiSession #%d test failed' % (i,)), oTxsSession);
2479 reporter.log('MultiSession #%d exceeded concurrent guest session count, good' % (i,));
2480 break;
2481
2482 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr);
2483 if cCurSessions is not cMaxGuestSessions:
2484 return (reporter.error('Final session count %d, expected %d ' % (cCurSessions, cMaxGuestSessions,)), oTxsSession);
2485
2486 reporter.log2('Closing MultiSessions ...');
2487 for i in xrange(cMaxGuestSessions):
2488 # Close this session:
2489 oClosedGuestSession = aoMultiSessions[i].oGuestSession;
2490 fRc2 = aoMultiSessions[i].closeSession();
2491 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr)
2492 reporter.log2('MultiSession #%d count is %d' % (i, cCurSessions,));
2493 if fRc2 is False:
2494 fRc = reporter.error('Closing MultiSession #%d failed' % (i,));
2495 elif cCurSessions != cMaxGuestSessions - (i + 1):
2496 fRc = reporter.error('Expected %d session after closing #%d, got %d instead'
2497 % (cMaxGuestSessions - (i + 1), cCurSessions, i,));
2498 assert aoMultiSessions[i].oGuestSession is None or not fRc2;
2499 ## @todo any way to check that the session is closed other than the 'sessions' attribute?
2500
2501 # Try check that none of the remaining sessions got closed.
2502 try:
2503 aoGuestSessions = self.oTstDrv.oVBoxMgr.getArray(atTests[0][0].oGuest, 'sessions');
2504 except:
2505 return (reporter.errorXcpt('i=%d/%d' % (i, cMaxGuestSessions,)), oTxsSession);
2506 if oClosedGuestSession in aoGuestSessions:
2507 fRc = reporter.error('i=%d/%d: %s should not be in %s'
2508 % (i, cMaxGuestSessions, oClosedGuestSession, aoGuestSessions));
2509 if i + 1 < cMaxGuestSessions: # Not sure what xrange(2,2) does...
2510 for j in xrange(i + 1, cMaxGuestSessions):
2511 if aoMultiSessions[j].oGuestSession not in aoGuestSessions:
2512 fRc = reporter.error('i=%d/j=%d/%d: %s should be in %s'
2513 % (i, j, cMaxGuestSessions, aoMultiSessions[j].oGuestSession, aoGuestSessions));
2514 ## @todo any way to check that they work?
2515
2516 ## @todo Test session timeouts.
2517
2518 return (fRc, oTxsSession);
2519
2520 def testGuestCtrlSessionFileRefs(self, oSession, oTxsSession, oTestVm):
2521 """
2522 Tests the guest session file reference handling.
2523 """
2524
2525 # Find a file to play around with:
2526 sFile = self.oTstDrv.getGuestSystemFileForReading(oTestVm);
2527
2528 # Use credential defaults.
2529 oCreds = tdCtxCreds();
2530 oCreds.applyDefaultsIfNotSet(oTestVm);
2531
2532 # Number of stale guest files to create.
2533 cStaleFiles = 10;
2534
2535 #
2536 # Start a session.
2537 #
2538 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
2539 try:
2540 oGuest = oSession.o.console.guest;
2541 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionFileRefs");
2542 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
2543 except:
2544 return (reporter.errorXcpt(), oTxsSession);
2545
2546 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
2547 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
2548 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
2549 reporter.log('Session successfully started');
2550
2551 #
2552 # Open guest files and "forget" them (stale entries).
2553 # For them we don't have any references anymore intentionally.
2554 #
2555 reporter.log2('Opening stale files');
2556 fRc = True;
2557 for i in xrange(0, cStaleFiles):
2558 try:
2559 if self.oTstDrv.fpApiVer >= 5.0:
2560 oGuestSession.fileOpen(sFile, vboxcon.FileAccessMode_ReadOnly, vboxcon.FileOpenAction_OpenExisting, 0);
2561 else:
2562 oGuestSession.fileOpen(sFile, "r", "oe", 0);
2563 # Note: Use a timeout in the call above for not letting the stale processes
2564 # hanging around forever. This can happen if the installed Guest Additions
2565 # do not support terminating guest processes.
2566 except:
2567 fRc = reporter.errorXcpt('Opening stale file #%d failed:' % (i,));
2568 break;
2569
2570 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
2571 except: fRc = reporter.errorXcpt();
2572 else:
2573 if cFiles != cStaleFiles:
2574 fRc = reporter.error('Got %d stale files, expected %d' % (cFiles, cStaleFiles));
2575
2576 if fRc is True:
2577 #
2578 # Open non-stale files and close them again.
2579 #
2580 reporter.log2('Opening non-stale files');
2581 aoFiles = [];
2582 for i in xrange(0, cStaleFiles):
2583 try:
2584 if self.oTstDrv.fpApiVer >= 5.0:
2585 oCurFile = oGuestSession.fileOpen(sFile, vboxcon.FileAccessMode_ReadOnly,
2586 vboxcon.FileOpenAction_OpenExisting, 0);
2587 else:
2588 oCurFile = oGuestSession.fileOpen(sFile, "r", "oe", 0);
2589 aoFiles.append(oCurFile);
2590 except:
2591 fRc = reporter.errorXcpt('Opening non-stale file #%d failed:' % (i,));
2592 break;
2593
2594 # Check the count.
2595 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
2596 except: fRc = reporter.errorXcpt();
2597 else:
2598 if cFiles != cStaleFiles * 2:
2599 fRc = reporter.error('Got %d total files, expected %d' % (cFiles, cStaleFiles * 2));
2600
2601 # Close them.
2602 reporter.log2('Closing all non-stale files again ...');
2603 for i, oFile in enumerate(aoFiles):
2604 try:
2605 oFile.close();
2606 except:
2607 fRc = reporter.errorXcpt('Closing non-stale file #%d failed:' % (i,));
2608
2609 # Check the count again.
2610 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
2611 except: fRc = reporter.errorXcpt();
2612 # Here we count the stale files (that is, files we don't have a reference
2613 # anymore for) and the opened and then closed non-stale files (that we still keep
2614 # a reference in aoFiles[] for).
2615 if cFiles != cStaleFiles:
2616 fRc = reporter.error('Got %d total files, expected %d' % (cFiles, cStaleFiles));
2617
2618 #
2619 # Check that all (referenced) non-stale files are now in the "closed" state.
2620 #
2621 reporter.log2('Checking statuses of all non-stale files ...');
2622 for i, oFile in enumerate(aoFiles):
2623 try:
2624 eFileStatus = aoFiles[i].status;
2625 except:
2626 fRc = reporter.errorXcpt('Checking status of file #%d failed:' % (i,));
2627 else:
2628 if eFileStatus != vboxcon.FileStatus_Closed:
2629 fRc = reporter.error('Non-stale file #%d has status %d, expected %d'
2630 % (i, eFileStatus, vboxcon.FileStatus_Closed));
2631
2632 if fRc is True:
2633 reporter.log2('All non-stale files closed');
2634
2635 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
2636 except: fRc = reporter.errorXcpt();
2637 else: reporter.log2('Final guest session file count: %d' % (cFiles,));
2638
2639 #
2640 # Now try to close the session and see what happens.
2641 # Note! Session closing is why we've been doing all the 'if fRc is True' stuff above rather than returning.
2642 #
2643 reporter.log2('Closing guest session ...');
2644 try:
2645 oGuestSession.close();
2646 except:
2647 fRc = reporter.errorXcpt('Testing for stale processes failed:');
2648
2649 return (fRc, oTxsSession);
2650
2651 #def testGuestCtrlSessionDirRefs(self, oSession, oTxsSession, oTestVm):
2652 # """
2653 # Tests the guest session directory reference handling.
2654 # """
2655
2656 # fRc = True;
2657 # return (fRc, oTxsSession);
2658
2659 def testGuestCtrlSessionProcRefs(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
2660 """
2661 Tests the guest session process reference handling.
2662 """
2663
2664 sCmd = self.oTstDrv.getGuestSystemShell(oTestVm);
2665 asArgs = [sCmd,];
2666
2667 # Use credential defaults.
2668 oCreds = tdCtxCreds();
2669 oCreds.applyDefaultsIfNotSet(oTestVm);
2670
2671 # Number of stale guest processes to create.
2672 cStaleProcs = 10;
2673
2674 #
2675 # Start a session.
2676 #
2677 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
2678 try:
2679 oGuest = oSession.o.console.guest;
2680 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionProcRefs");
2681 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
2682 except:
2683 return (reporter.errorXcpt(), oTxsSession);
2684
2685 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
2686 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
2687 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
2688 reporter.log('Session successfully started');
2689
2690 #
2691 # Fire off forever-running processes and "forget" them (stale entries).
2692 # For them we don't have any references anymore intentionally.
2693 #
2694 reporter.log2('Starting stale processes...');
2695 fRc = True;
2696 for i in xrange(0, cStaleProcs):
2697 try:
2698 oGuestSession.processCreate(sCmd,
2699 asArgs if self.oTstDrv.fpApiVer >= 5.0 else asArgs[1:], [],
2700 [ vboxcon.ProcessCreateFlag_WaitForStdOut ], 30 * 1000);
2701 # Note: Use a timeout in the call above for not letting the stale processes
2702 # hanging around forever. This can happen if the installed Guest Additions
2703 # do not support terminating guest processes.
2704 except:
2705 fRc = reporter.errorXcpt('Creating stale process #%d failed:' % (i,));
2706 break;
2707
2708 try: cProcesses = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
2709 except: fRc = reporter.errorXcpt();
2710 else:
2711 if cProcesses != cStaleProcs:
2712 fRc = reporter.error('Got %d stale processes, expected %d' % (cProcesses, cStaleProcs));
2713
2714 if fRc is True:
2715 #
2716 # Fire off non-stale processes and wait for termination.
2717 #
2718 if oTestVm.isWindows() or oTestVm.isOS2():
2719 asArgs = [ sCmd, '/C', 'dir', '/S', self.oTstDrv.getGuestSystemDir(oTestVm), ];
2720 else:
2721 asArgs = [ sCmd, '-c', 'ls -la ' + self.oTstDrv.getGuestSystemDir(oTestVm), ];
2722 reporter.log2('Starting non-stale processes...');
2723 aoProcesses = [];
2724 for i in xrange(0, cStaleProcs):
2725 try:
2726 oCurProc = oGuestSession.processCreate(sCmd, asArgs if self.oTstDrv.fpApiVer >= 5.0 else asArgs[1:],
2727 [], [], 0); # Infinite timeout.
2728 aoProcesses.append(oCurProc);
2729 except:
2730 fRc = reporter.errorXcpt('Creating non-stale process #%d failed:' % (i,));
2731 break;
2732
2733 reporter.log2('Waiting for non-stale processes to terminate...');
2734 for i, oProcess in enumerate(aoProcesses):
2735 try:
2736 eWaitResult = oProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], 120 * 1000);
2737 eProcessStatus = oProcess.status;
2738 except:
2739 fRc = reporter.errorXcpt('Waiting for non-stale process #%d failed:' % (i,));
2740 else:
2741 if eProcessStatus != vboxcon.ProcessStatus_TerminatedNormally:
2742 fRc = reporter.error('Waiting for non-stale processes #%d resulted in status %d, expected %d (wr=%d)'
2743 % (i, eProcessStatus, vboxcon.ProcessStatus_TerminatedNormally, eWaitResult));
2744
2745 try: cProcesses = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
2746 except: fRc = reporter.errorXcpt();
2747 else:
2748 # Here we count the stale processes (that is, processes we don't have a reference
2749 # anymore for) and the started + terminated non-stale processes (that we still keep
2750 # a reference in aoProcesses[] for).
2751 if cProcesses != (cStaleProcs * 2):
2752 fRc = reporter.error('Got %d total processes, expected %d' % (cProcesses, cStaleProcs));
2753
2754 if fRc is True:
2755 reporter.log2('All non-stale processes terminated');
2756
2757 #
2758 # Fire off non-stale blocking processes which are terminated via terminate().
2759 #
2760 if oTestVm.isWindows() or oTestVm.isOS2():
2761 asArgs = [ sCmd, '/C', 'pause'];
2762 else:
2763 asArgs = [ sCmd ];
2764 reporter.log2('Starting blocking processes...');
2765 aoProcesses = [];
2766 for i in xrange(0, cStaleProcs):
2767 try:
2768 oCurProc = oGuestSession.processCreate(sCmd, asArgs if self.oTstDrv.fpApiVer >= 5.0 else asArgs[1:],
2769 [], [], 30 * 1000);
2770 # Note: Use a timeout in the call above for not letting the stale processes
2771 # hanging around forever. This can happen if the installed Guest Additions
2772 # do not support terminating guest processes.
2773 aoProcesses.append(oCurProc);
2774 except:
2775 fRc = reporter.errorXcpt('Creating non-stale blocking process #%d failed:' % (i,));
2776 break;
2777
2778 reporter.log2('Terminating blocking processes...');
2779 for i, oProcess in enumerate(aoProcesses):
2780 try:
2781 oProcess.terminate();
2782 except: # Termination might not be supported, just skip and log it.
2783 reporter.logXcpt('Termination of blocking process #%d failed, skipped:' % (i,));
2784
2785 # There still should be 20 processes because we terminated the 10 newest ones.
2786 try: cProcesses = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
2787 except: fRc = reporter.errorXcpt();
2788 else:
2789 if cProcesses != (cStaleProcs * 2):
2790 fRc = reporter.error('Got %d total processes, expected %d' % (cProcesses, cStaleProcs));
2791 reporter.log2('Final guest session processes count: %d' % (cProcesses,));
2792
2793 #
2794 # Now try to close the session and see what happens.
2795 #
2796 reporter.log2('Closing guest session ...');
2797 try:
2798 oGuestSession.close();
2799 except:
2800 fRc = reporter.errorXcpt('Testing for stale processes failed:');
2801
2802 return (fRc, oTxsSession);
2803
2804 def testGuestCtrlExec(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals,too-many-statements
2805 """
2806 Tests the basic execution feature.
2807 """
2808
2809 # Paths:
2810 sVBoxControl = None; ## @todo Get path of installed Guest Additions. Later.
2811 sShell = self.oTstDrv.getGuestSystemShell(oTestVm);
2812 sShellOpt = '/C' if oTestVm.isWindows() or oTestVm.isOS2() else '-c';
2813 sSystemDir = self.oTstDrv.getGuestSystemDir(oTestVm);
2814 sFileForReading = self.oTstDrv.getGuestSystemFileForReading(oTestVm);
2815 if oTestVm.isWindows() or oTestVm.isOS2():
2816 sImageOut = self.oTstDrv.getGuestSystemShell(oTestVm);
2817 if oTestVm.isWindows():
2818 sVBoxControl = "C:\\Program Files\\Oracle\\VirtualBox Guest Additions\\VBoxControl.exe";
2819 else:
2820 sImageOut = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'ls');
2821 if oTestVm.isLinux(): ## @todo check solaris and darwin.
2822 sVBoxControl = "/usr/bin/VBoxControl"; # Symlink
2823
2824 # Use credential defaults.
2825 oCreds = tdCtxCreds();
2826 oCreds.applyDefaultsIfNotSet(oTestVm);
2827
2828 atInvalid = [
2829 # Invalid parameters.
2830 [ tdTestExec(), tdTestResultExec() ],
2831 # Non-existent / invalid image.
2832 [ tdTestExec(sCmd = "non-existent"), tdTestResultExec() ],
2833 [ tdTestExec(sCmd = "non-existent2"), tdTestResultExec() ],
2834 # Use an invalid format string.
2835 [ tdTestExec(sCmd = "%$%%%&"), tdTestResultExec() ],
2836 # More stuff.
2837 [ tdTestExec(sCmd = u"ƒ‰‹ˆ÷‹¸"), tdTestResultExec() ],
2838 [ tdTestExec(sCmd = "???://!!!"), tdTestResultExec() ],
2839 [ tdTestExec(sCmd = "<>!\\"), tdTestResultExec() ],
2840 # Enable as soon as ERROR_BAD_DEVICE is implemented.
2841 #[ tdTestExec(sCmd = "CON", tdTestResultExec() ],
2842 ];
2843
2844 atExec = [];
2845 if oTestVm.isWindows() or oTestVm.isOS2():
2846 atExec += [
2847 # Basic execution.
2848 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
2849 tdTestResultExec(fRc = True) ],
2850 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sFileForReading ]),
2851 tdTestResultExec(fRc = True) ],
2852 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir + '\\nonexist.dll' ]),
2853 tdTestResultExec(fRc = True, iExitCode = 1) ],
2854 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', '/wrongparam' ]),
2855 tdTestResultExec(fRc = True, iExitCode = 1) ],
2856 [ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'wrongcommand' ]),
2857 tdTestResultExec(fRc = True, iExitCode = 1) ],
2858 # StdOut.
2859 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
2860 tdTestResultExec(fRc = True) ],
2861 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stdout-non-existing' ]),
2862 tdTestResultExec(fRc = True, iExitCode = 1) ],
2863 # StdErr.
2864 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
2865 tdTestResultExec(fRc = True) ],
2866 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stderr-non-existing' ]),
2867 tdTestResultExec(fRc = True, iExitCode = 1) ],
2868 # StdOut + StdErr.
2869 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
2870 tdTestResultExec(fRc = True) ],
2871 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stdouterr-non-existing' ]),
2872 tdTestResultExec(fRc = True, iExitCode = 1) ],
2873 ];
2874 # atExec.extend([
2875 # FIXME: Failing tests.
2876 # Environment variables.
2877 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_NONEXIST' ],
2878 # tdTestResultExec(fRc = True, iExitCode = 1) ]
2879 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'windir' ],
2880 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2881 # tdTestResultExec(fRc = True, sBuf = 'windir=C:\\WINDOWS\r\n') ],
2882 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
2883 # aEnv = [ 'TEST_FOO=BAR' ],
2884 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2885 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ],
2886 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
2887 # aEnv = [ 'TEST_FOO=BAR', 'TEST_BAZ=BAR' ],
2888 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2889 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ]
2890
2891 ## @todo Create some files (or get files) we know the output size of to validate output length!
2892 ## @todo Add task which gets killed at some random time while letting the guest output something.
2893 #];
2894 else:
2895 atExec += [
2896 # Basic execution.
2897 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '-R', sSystemDir ]),
2898 tdTestResultExec(fRc = True) ],
2899 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sFileForReading ]),
2900 tdTestResultExec(fRc = True) ],
2901 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '--wrong-parameter' ]),
2902 tdTestResultExec(fRc = True, iExitCode = 2) ],
2903 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/non/existent' ]),
2904 tdTestResultExec(fRc = True, iExitCode = 2) ],
2905 [ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'wrongcommand' ]),
2906 tdTestResultExec(fRc = True, iExitCode = 127) ],
2907 # StdOut.
2908 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
2909 tdTestResultExec(fRc = True) ],
2910 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stdout-non-existing' ]),
2911 tdTestResultExec(fRc = True, iExitCode = 2) ],
2912 # StdErr.
2913 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
2914 tdTestResultExec(fRc = True) ],
2915 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stderr-non-existing' ]),
2916 tdTestResultExec(fRc = True, iExitCode = 2) ],
2917 # StdOut + StdErr.
2918 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
2919 tdTestResultExec(fRc = True) ],
2920 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stdouterr-non-existing' ]),
2921 tdTestResultExec(fRc = True, iExitCode = 2) ],
2922 ];
2923 # atExec.extend([
2924 # FIXME: Failing tests.
2925 # Environment variables.
2926 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_NONEXIST' ],
2927 # tdTestResultExec(fRc = True, iExitCode = 1) ]
2928 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'windir' ],
2929 #
2930 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2931 # tdTestResultExec(fRc = True, sBuf = 'windir=C:\\WINDOWS\r\n') ],
2932 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
2933 # aEnv = [ 'TEST_FOO=BAR' ],
2934 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2935 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ],
2936 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
2937 # aEnv = [ 'TEST_FOO=BAR', 'TEST_BAZ=BAR' ],
2938 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2939 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ]
2940
2941 ## @todo Create some files (or get files) we know the output size of to validate output length!
2942 ## @todo Add task which gets killed at some random time while letting the guest output something.
2943 #];
2944
2945 #
2946 for iExitCode in xrange(0, 127):
2947 atExec.append([ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'exit %s' % iExitCode ]),
2948 tdTestResultExec(fRc = True, iExitCode = iExitCode) ]);
2949
2950 if sVBoxControl \
2951 and self.oTstDrv.fpApiVer >= 6.0: # Investigate with this doesn't work on (<) 5.2.
2952 # Paths with spaces on windows.
2953 atExec.append([ tdTestExec(sCmd = sVBoxControl, asArgs = [ sVBoxControl, 'version' ],
2954 afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut,
2955 vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2956 tdTestResultExec(fRc = True) ]);
2957
2958 # Test very long arguments.
2959 if self.oTstDrv.fpApiVer >= 6.1:
2960 if oTestVm.isWindows() \
2961 or oTestVm.isOS2():
2962 sEcho = sShell;
2963 sEchoSuffix = '';
2964 else:
2965 sEcho = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'echo');
2966 # The suffix acts as an indicator / beacon to see if the actual (random) args were received fully.
2967 sEchoSuffix = "-n";
2968
2969 for _ in xrange(0, 16):
2970 ## @todo Check limits; on Ubuntu with 256KB IPRT returns VERR_NOT_IMPLEMENTED.
2971 atExec.append([ tdTestExec(sCmd = sEcho,
2972 asArgs = [ sEcho, sShellOpt,
2973 self.oTestFiles.generateFilenameEx(128 * 1024, 2048), sEchoSuffix ],
2974 afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut,
2975 vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2976 tdTestResultExec(fRc = True) ]);
2977
2978 # Build up the final test array for the first batch.
2979 atTests = atInvalid + atExec;
2980
2981 #
2982 # First batch: One session per guest process.
2983 #
2984 reporter.log('One session per guest process ...');
2985 fRc = True;
2986 for (i, tTest) in enumerate(atTests):
2987 oCurTest = tTest[0] # type: tdTestExec
2988 oCurRes = tTest[1] # type: tdTestResultExec
2989 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
2990 fRc2, oCurGuestSession = oCurTest.createSession('testGuestCtrlExec: Test #%d' % (i,));
2991 if fRc2 is not True:
2992 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
2993 break;
2994 fRc = self.gctrlExecDoTest(i, oCurTest, oCurRes, oCurGuestSession) and fRc;
2995 fRc = oCurTest.closeSession() and fRc;
2996
2997 reporter.log('Execution of all tests done, checking for stale sessions');
2998
2999 # No sessions left?
3000 try:
3001 aSessions = self.oTstDrv.oVBoxMgr.getArray(oSession.o.console.guest, 'sessions');
3002 except:
3003 fRc = reporter.errorXcpt();
3004 else:
3005 cSessions = len(aSessions);
3006 if cSessions != 0:
3007 fRc = reporter.error('Found %d stale session(s), expected 0:' % (cSessions,));
3008 for (i, aSession) in enumerate(aSessions):
3009 try: reporter.log(' Stale session #%d ("%s")' % (aSession.id, aSession.name));
3010 except: reporter.errorXcpt();
3011
3012 if fRc is not True:
3013 return (fRc, oTxsSession);
3014
3015 reporter.log('Now using one guest session for all tests ...');
3016
3017 #
3018 # Second batch: One session for *all* guest processes.
3019 #
3020
3021 # Create session.
3022 reporter.log('Creating session for all tests ...');
3023 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start, ];
3024 try:
3025 oGuest = oSession.o.console.guest;
3026 oCurGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain,
3027 'testGuestCtrlExec: One session for all tests');
3028 except:
3029 return (reporter.errorXcpt(), oTxsSession);
3030
3031 try:
3032 eWaitResult = oCurGuestSession.waitForArray(aeWaitFor, 30 * 1000);
3033 except:
3034 fRc = reporter.errorXcpt('Waiting for guest session to start failed:');
3035 else:
3036 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3037 fRc = reporter.error('Session did not start successfully, returned wait result: %d' % (eWaitResult,));
3038 else:
3039 reporter.log('Session successfully started');
3040
3041 # Do the tests within this session.
3042 for (i, tTest) in enumerate(atTests):
3043 oCurTest = tTest[0] # type: tdTestExec
3044 oCurRes = tTest[1] # type: tdTestResultExec
3045
3046 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3047 fRc = self.gctrlExecDoTest(i, oCurTest, oCurRes, oCurGuestSession);
3048 if fRc is False:
3049 break;
3050
3051 # Close the session.
3052 reporter.log2('Closing guest session ...');
3053 try:
3054 oCurGuestSession.close();
3055 oCurGuestSession = None;
3056 except:
3057 fRc = reporter.errorXcpt('Closing guest session failed:');
3058
3059 # No sessions left?
3060 reporter.log('Execution of all tests done, checking for stale sessions again');
3061 try: cSessions = len(self.oTstDrv.oVBoxMgr.getArray(oSession.o.console.guest, 'sessions'));
3062 except: fRc = reporter.errorXcpt();
3063 else:
3064 if cSessions != 0:
3065 fRc = reporter.error('Found %d stale session(s), expected 0' % (cSessions,));
3066 return (fRc, oTxsSession);
3067
3068 def threadForTestGuestCtrlSessionReboot(self, oGuestProcess):
3069 """
3070 Thread routine which waits for the stale guest process getting terminated (or some error)
3071 while the main test routine reboots the guest. It then compares the expected guest process result
3072 and logs an error if appropriate.
3073 """
3074 reporter.log('Waiting for process to get terminated at reboot ...');
3075 try:
3076 eWaitResult = oGuestProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate ], 5 * 60 * 1000);
3077 except:
3078 return reporter.errorXcpt('waitForArray failed');
3079 try:
3080 eStatus = oGuestProcess.status
3081 except:
3082 return reporter.errorXcpt('failed to get status (wait result %d)' % (eWaitResult,));
3083
3084 if eWaitResult == vboxcon.ProcessWaitResult_Terminate and eStatus == vboxcon.ProcessStatus_Down:
3085 reporter.log('Stale process was correctly terminated (status: down)');
3086 return True;
3087
3088 return reporter.error('Process wait across reboot failed: eWaitResult=%d, expected %d; eStatus=%d, expected %d'
3089 % (eWaitResult, vboxcon.ProcessWaitResult_Terminate, eStatus, vboxcon.ProcessStatus_Down,));
3090
3091 def testGuestCtrlSessionReboot(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
3092 """
3093 Tests guest object notifications when a guest gets rebooted / shutdown.
3094
3095 These notifications gets sent from the guest sessions in order to make API clients
3096 aware of guest session changes.
3097
3098 To test that we create a stale guest process and trigger a reboot of the guest.
3099 """
3100
3101 ## @todo backport fixes to 6.0 and maybe 5.2
3102 if self.oTstDrv.fpApiVer <= 6.0:
3103 reporter.log('Skipping: Required fixes not yet backported!');
3104 return None;
3105
3106 # Use credential defaults.
3107 oCreds = tdCtxCreds();
3108 oCreds.applyDefaultsIfNotSet(oTestVm);
3109
3110 fRc = True;
3111
3112 #
3113 # Start a session.
3114 #
3115 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
3116 try:
3117 oGuest = oSession.o.console.guest;
3118 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionReboot");
3119 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
3120 except:
3121 return (reporter.errorXcpt(), oTxsSession);
3122
3123 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
3124 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3125 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
3126 reporter.log('Session successfully started');
3127
3128 #
3129 # Create a process.
3130 #
3131 sImage = self.oTstDrv.getGuestSystemShell(oTestVm);
3132 asArgs = [ sImage, ];
3133 aEnv = [];
3134 afFlags = [];
3135 try:
3136 oGuestProcess = oGuestSession.processCreate(sImage,
3137 asArgs if self.oTstDrv.fpApiVer >= 5.0 else asArgs[1:], aEnv, afFlags,
3138 30 * 1000);
3139 except:
3140 fRc = reporter.error('Failed to start shell process (%s)' % (sImage,));
3141 else:
3142 try:
3143 eWaitResult = oGuestProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3144 except:
3145 fRc = reporter.errorXcpt('Waiting for shell process (%s) to start failed' % (sImage,));
3146 else:
3147 # Check the result and state:
3148 try: eStatus = oGuestProcess.status;
3149 except: fRc = reporter.errorXcpt('Waiting for shell process (%s) to start failed' % (sImage,));
3150 else:
3151 reporter.log2('Starting process wait result returned: %d; Process status is: %d' % (eWaitResult, eStatus,));
3152 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3153 fRc = reporter.error('wait for ProcessWaitForFlag_Start failed: %d, expected %d (Start)'
3154 % (eWaitResult, vboxcon.ProcessWaitResult_Start,));
3155 elif eStatus != vboxcon.ProcessStatus_Started:
3156 fRc = reporter.error('Unexpected process status after startup: %d, wanted %d (Started)'
3157 % (eStatus, vboxcon.ProcessStatus_Started,));
3158 else:
3159 # Create a thread that waits on the process to terminate
3160 reporter.log('Creating reboot thread ...');
3161 oThreadReboot = threading.Thread(target = self.threadForTestGuestCtrlSessionReboot,
3162 args = (oGuestProcess,),
3163 name = ('threadForTestGuestCtrlSessionReboot'));
3164 oThreadReboot.setDaemon(True);
3165 oThreadReboot.start();
3166
3167 # Not sure why this fudge is needed...
3168 reporter.log('5 second wait fudge before triggering reboot ...');
3169 self.oTstDrv.sleep(5);
3170
3171 # Do the reboot.
3172 reporter.log('Rebooting guest and reconnecting TXS ...');
3173 (oSession, oTxsSession) = self.oTstDrv.txsRebootAndReconnectViaTcp(oSession, oTxsSession,
3174 cMsTimeout = 3 * 60000);
3175 if not oSession or not oTxsSession:
3176 try: oGuestProcess.terminate();
3177 except: reporter.logXcpt();
3178 fRc = False;
3179
3180 reporter.log('Waiting for thread to finish ...');
3181 oThreadReboot.join();
3182
3183 #
3184 # Try make sure we don't leave with a stale process on failure.
3185 #
3186 try: oGuestProcess.terminate();
3187 except: reporter.logXcpt();
3188
3189 #
3190 # Close the session.
3191 #
3192 reporter.log2('Closing guest session ...');
3193 try:
3194 oGuestSession.close();
3195 except:
3196 fRc = reporter.errorXcpt();
3197
3198 return (fRc, oTxsSession);
3199
3200 def testGuestCtrlExecTimeout(self, oSession, oTxsSession, oTestVm):
3201 """
3202 Tests handling of timeouts of started guest processes.
3203 """
3204
3205 sShell = self.oTstDrv.getGuestSystemShell(oTestVm);
3206
3207 # Use credential defaults.
3208 oCreds = tdCtxCreds();
3209 oCreds.applyDefaultsIfNotSet(oTestVm);
3210
3211 #
3212 # Create a session.
3213 #
3214 try:
3215 oGuest = oSession.o.console.guest;
3216 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlExecTimeout");
3217 eWaitResult = oGuestSession.waitForArray([ vboxcon.GuestSessionWaitForFlag_Start, ], 30 * 1000);
3218 except:
3219 return (reporter.errorXcpt(), oTxsSession);
3220
3221 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
3222 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3223 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
3224 reporter.log('Session successfully started');
3225
3226 #
3227 # Create a process which never terminates and should timeout when
3228 # waiting for termination.
3229 #
3230 fRc = True;
3231 try:
3232 oCurProcess = oGuestSession.processCreate(sShell, [sShell,] if self.oTstDrv.fpApiVer >= 5.0 else [],
3233 [], [], 30 * 1000);
3234 except:
3235 fRc = reporter.errorXcpt();
3236 else:
3237 reporter.log('Waiting for process 1 being started ...');
3238 try:
3239 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3240 except:
3241 fRc = reporter.errorXcpt();
3242 else:
3243 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3244 fRc = reporter.error('Waiting for process 1 to start failed, got status %d' % (eWaitResult,));
3245 else:
3246 for msWait in (1, 32, 2000,):
3247 reporter.log('Waiting for process 1 to time out within %sms ...' % (msWait,));
3248 try:
3249 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], msWait);
3250 except:
3251 fRc = reporter.errorXcpt();
3252 break;
3253 if eWaitResult != vboxcon.ProcessWaitResult_Timeout:
3254 fRc = reporter.error('Waiting for process 1 did not time out in %sms as expected: %d'
3255 % (msWait, eWaitResult,));
3256 break;
3257 reporter.log('Waiting for process 1 timed out in %u ms, good' % (msWait,));
3258
3259 try:
3260 oCurProcess.terminate();
3261 except:
3262 reporter.errorXcpt();
3263 oCurProcess = None;
3264
3265 #
3266 # Create another process that doesn't terminate, but which will be killed by VBoxService
3267 # because it ran out of execution time (3 seconds).
3268 #
3269 try:
3270 oCurProcess = oGuestSession.processCreate(sShell, [sShell,] if self.oTstDrv.fpApiVer >= 5.0 else [],
3271 [], [], 3 * 1000);
3272 except:
3273 fRc = reporter.errorXcpt();
3274 else:
3275 reporter.log('Waiting for process 2 being started ...');
3276 try:
3277 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3278 except:
3279 fRc = reporter.errorXcpt();
3280 else:
3281 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3282 fRc = reporter.error('Waiting for process 2 to start failed, got status %d' % (eWaitResult,));
3283 else:
3284 reporter.log('Waiting for process 2 to get killed for running out of execution time ...');
3285 try:
3286 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], 15 * 1000);
3287 except:
3288 fRc = reporter.errorXcpt();
3289 else:
3290 if eWaitResult != vboxcon.ProcessWaitResult_Timeout:
3291 fRc = reporter.error('Waiting for process 2 did not time out when it should, got wait result %d'
3292 % (eWaitResult,));
3293 else:
3294 reporter.log('Waiting for process 2 did not time out, good: %s' % (eWaitResult,));
3295 try:
3296 eStatus = oCurProcess.status;
3297 except:
3298 fRc = reporter.errorXcpt();
3299 else:
3300 if eStatus != vboxcon.ProcessStatus_TimedOutKilled:
3301 fRc = reporter.error('Status of process 2 wrong; excepted %d, got %d'
3302 % (vboxcon.ProcessStatus_TimedOutKilled, eStatus));
3303 else:
3304 reporter.log('Status of process 2 is TimedOutKilled (%d) is it should be.'
3305 % (vboxcon.ProcessStatus_TimedOutKilled,));
3306 try:
3307 oCurProcess.terminate();
3308 except:
3309 reporter.logXcpt();
3310 oCurProcess = None;
3311
3312 #
3313 # Clean up the session.
3314 #
3315 try:
3316 oGuestSession.close();
3317 except:
3318 fRc = reporter.errorXcpt();
3319
3320 return (fRc, oTxsSession);
3321
3322 def testGuestCtrlDirCreate(self, oSession, oTxsSession, oTestVm):
3323 """
3324 Tests creation of guest directories.
3325 """
3326
3327 sScratch = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'testGuestCtrlDirCreate');
3328
3329 atTests = [
3330 # Invalid stuff.
3331 [ tdTestDirCreate(sDirectory = '' ), tdTestResultFailure() ],
3332 # More unusual stuff.
3333 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin('..', '.') ), tdTestResultFailure() ],
3334 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin('..', '..') ), tdTestResultFailure() ],
3335 [ tdTestDirCreate(sDirectory = '..' ), tdTestResultFailure() ],
3336 [ tdTestDirCreate(sDirectory = '../' ), tdTestResultFailure() ],
3337 [ tdTestDirCreate(sDirectory = '../../' ), tdTestResultFailure() ],
3338 [ tdTestDirCreate(sDirectory = '/' ), tdTestResultFailure() ],
3339 [ tdTestDirCreate(sDirectory = '/..' ), tdTestResultFailure() ],
3340 [ tdTestDirCreate(sDirectory = '/../' ), tdTestResultFailure() ],
3341 ];
3342 if oTestVm.isWindows() or oTestVm.isOS2():
3343 atTests.extend([
3344 [ tdTestDirCreate(sDirectory = 'C:\\' ), tdTestResultFailure() ],
3345 [ tdTestDirCreate(sDirectory = 'C:\\..' ), tdTestResultFailure() ],
3346 [ tdTestDirCreate(sDirectory = 'C:\\..\\' ), tdTestResultFailure() ],
3347 [ tdTestDirCreate(sDirectory = 'C:/' ), tdTestResultFailure() ],
3348 [ tdTestDirCreate(sDirectory = 'C:/.' ), tdTestResultFailure() ],
3349 [ tdTestDirCreate(sDirectory = 'C:/./' ), tdTestResultFailure() ],
3350 [ tdTestDirCreate(sDirectory = 'C:/..' ), tdTestResultFailure() ],
3351 [ tdTestDirCreate(sDirectory = 'C:/../' ), tdTestResultFailure() ],
3352 [ tdTestDirCreate(sDirectory = '\\\\uncrulez\\foo' ), tdTestResultFailure() ],
3353 ]);
3354 atTests.extend([
3355 # Existing directories and files.
3356 [ tdTestDirCreate(sDirectory = self.oTstDrv.getGuestSystemDir(oTestVm) ), tdTestResultFailure() ],
3357 [ tdTestDirCreate(sDirectory = self.oTstDrv.getGuestSystemShell(oTestVm) ), tdTestResultFailure() ],
3358 [ tdTestDirCreate(sDirectory = self.oTstDrv.getGuestSystemFileForReading(oTestVm) ), tdTestResultFailure() ],
3359 # Creating directories.
3360 [ tdTestDirCreate(sDirectory = sScratch ), tdTestResultSuccess() ],
3361 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo', 'bar', 'baz'),
3362 afFlags = (vboxcon.DirectoryCreateFlag_Parents,) ), tdTestResultSuccess() ],
3363 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo', 'bar', 'baz'),
3364 afFlags = (vboxcon.DirectoryCreateFlag_Parents,) ), tdTestResultSuccess() ],
3365 # Long random names.
3366 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(36, 28))),
3367 tdTestResultSuccess() ],
3368 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(140, 116))),
3369 tdTestResultSuccess() ],
3370 # Too long names. ASSUMES a guests has a 255 filename length limitation.
3371 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(2048, 256))),
3372 tdTestResultFailure() ],
3373 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(2048, 256))),
3374 tdTestResultFailure() ],
3375 # Missing directory in path.
3376 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo1', 'bar') ), tdTestResultFailure() ],
3377 ]);
3378
3379 fRc = True;
3380 for (i, tTest) in enumerate(atTests):
3381 oCurTest = tTest[0] # type: tdTestDirCreate
3382 oCurRes = tTest[1] # type: tdTestResult
3383 reporter.log('Testing #%d, sDirectory="%s" ...' % (i, oCurTest.sDirectory));
3384
3385 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3386 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirCreate: Test #%d' % (i,));
3387 if fRc is False:
3388 return reporter.error('Test #%d failed: Could not create session' % (i,));
3389
3390 fRc = self.gctrlCreateDir(oCurTest, oCurRes, oCurGuestSession);
3391
3392 fRc = oCurTest.closeSession() and fRc;
3393 if fRc is False:
3394 fRc = reporter.error('Test #%d failed' % (i,));
3395
3396 return (fRc, oTxsSession);
3397
3398 def testGuestCtrlDirCreateTemp(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
3399 """
3400 Tests creation of temporary directories.
3401 """
3402
3403 sSystemDir = self.oTstDrv.getGuestSystemDir(oTestVm);
3404 atTests = [
3405 # Invalid stuff (template must have one or more trailin 'X'es (upper case only), or a cluster of three or more).
3406 [ tdTestDirCreateTemp(sDirectory = ''), tdTestResultFailure() ],
3407 [ tdTestDirCreateTemp(sDirectory = sSystemDir, fMode = 1234), tdTestResultFailure() ],
3408 [ tdTestDirCreateTemp(sTemplate = 'xXx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3409 [ tdTestDirCreateTemp(sTemplate = 'xxx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3410 [ tdTestDirCreateTemp(sTemplate = 'XXx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3411 [ tdTestDirCreateTemp(sTemplate = 'bar', sDirectory = 'whatever', fMode = 0o700), tdTestResultFailure() ],
3412 [ tdTestDirCreateTemp(sTemplate = 'foo', sDirectory = 'it is not used', fMode = 0o700), tdTestResultFailure() ],
3413 [ tdTestDirCreateTemp(sTemplate = 'X,so', sDirectory = 'pointless test', fMode = 0o700), tdTestResultFailure() ],
3414 # Non-existing stuff.
3415 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX',
3416 sDirectory = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'non', 'existing')),
3417 tdTestResultFailure() ],
3418 # Working stuff:
3419 [ tdTestDirCreateTemp(sTemplate = 'X', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3420 [ tdTestDirCreateTemp(sTemplate = 'XX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3421 [ tdTestDirCreateTemp(sTemplate = 'XXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3422 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
3423 tdTestResultFailure() ],
3424 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
3425 tdTestResultFailure() ],
3426 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
3427 tdTestResultFailure() ],
3428 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
3429 tdTestResultFailure() ],
3430 ## @todo test fSecure and pass weird fMode values once these parameters are implemented in the API.
3431 ];
3432
3433 fRc = True;
3434 for (i, tTest) in enumerate(atTests):
3435 oCurTest = tTest[0] # type: tdTestDirCreateTemp
3436 oCurRes = tTest[1] # type: tdTestResult
3437 reporter.log('Testing #%d, sTemplate="%s", fMode=%#o, path="%s", secure="%s" ...' %
3438 (i, oCurTest.sTemplate, oCurTest.fMode, oCurTest.sDirectory, oCurTest.fSecure));
3439
3440 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3441 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirCreateTemp: Test #%d' % (i,));
3442 if fRc is False:
3443 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
3444 break;
3445
3446 sDirTemp = '';
3447 try:
3448 sDirTemp = oCurGuestSession.directoryCreateTemp(oCurTest.sTemplate, oCurTest.fMode,
3449 oCurTest.sDirectory, oCurTest.fSecure);
3450 except:
3451 if oCurRes.fRc is True:
3452 fRc = reporter.errorXcpt('Creating temp directory "%s" failed:' % (oCurTest.sDirectory,));
3453 else:
3454 reporter.logXcpt('Creating temp directory "%s" failed expectedly, skipping:' % (oCurTest.sDirectory,));
3455 else:
3456 reporter.log2('Temporary directory is: "%s"' % (limitString(sDirTemp),));
3457 if not sDirTemp:
3458 fRc = reporter.error('Resulting directory is empty!');
3459 else:
3460 ## @todo This does not work for some unknown reason.
3461 #try:
3462 # if self.oTstDrv.fpApiVer >= 5.0:
3463 # fExists = oCurGuestSession.directoryExists(sDirTemp, False);
3464 # else:
3465 # fExists = oCurGuestSession.directoryExists(sDirTemp);
3466 #except:
3467 # fRc = reporter.errorXcpt('sDirTemp=%s' % (sDirTemp,));
3468 #else:
3469 # if fExists is not True:
3470 # fRc = reporter.error('Test #%d failed: Temporary directory "%s" does not exists (%s)'
3471 # % (i, sDirTemp, fExists));
3472 try:
3473 oFsObjInfo = oCurGuestSession.fsObjQueryInfo(sDirTemp, False);
3474 eType = oFsObjInfo.type;
3475 except:
3476 fRc = reporter.errorXcpt('sDirTemp="%s"' % (sDirTemp,));
3477 else:
3478 reporter.log2('%s: eType=%s (dir=%d)' % (limitString(sDirTemp), eType, vboxcon.FsObjType_Directory,));
3479 if eType != vboxcon.FsObjType_Directory:
3480 fRc = reporter.error('Temporary directory "%s" not created as a directory: eType=%d'
3481 % (sDirTemp, eType));
3482 fRc = oCurTest.closeSession() and fRc;
3483 return (fRc, oTxsSession);
3484
3485 def testGuestCtrlDirRead(self, oSession, oTxsSession, oTestVm):
3486 """
3487 Tests opening and reading (enumerating) guest directories.
3488 """
3489
3490 sSystemDir = self.oTstDrv.getGuestSystemDir(oTestVm);
3491 atTests = [
3492 # Invalid stuff.
3493 [ tdTestDirRead(sDirectory = ''), tdTestResultDirRead() ],
3494 [ tdTestDirRead(sDirectory = sSystemDir, afFlags = [ 1234 ]), tdTestResultDirRead() ],
3495 [ tdTestDirRead(sDirectory = sSystemDir, sFilter = '*.foo'), tdTestResultDirRead() ],
3496 # Non-existing stuff.
3497 [ tdTestDirRead(sDirectory = oTestVm.pathJoin(sSystemDir, 'really-no-such-subdir')), tdTestResultDirRead() ],
3498 [ tdTestDirRead(sDirectory = oTestVm.pathJoin(sSystemDir, 'non', 'existing')), tdTestResultDirRead() ],
3499 ];
3500
3501 if oTestVm.isWindows() or oTestVm.isOS2():
3502 atTests.extend([
3503 # More unusual stuff.
3504 [ tdTestDirRead(sDirectory = 'z:\\'), tdTestResultDirRead() ],
3505 [ tdTestDirRead(sDirectory = '\\\\uncrulez\\foo'), tdTestResultDirRead() ],
3506 ]);
3507
3508 # Read the system directory (ASSUMES at least 5 files in it):
3509 # Windows 7+ has inaccessible system32/com/dmp directory that screws up this test, so skip it on windows:
3510 if not oTestVm.isWindows():
3511 atTests.append([ tdTestDirRead(sDirectory = sSystemDir),
3512 tdTestResultDirRead(fRc = True, cFiles = -5, cDirs = None) ]);
3513 ## @todo trailing slash
3514
3515 # Read from the test file set.
3516 atTests.extend([
3517 [ tdTestDirRead(sDirectory = self.oTestFiles.oEmptyDir.sPath),
3518 tdTestResultDirRead(fRc = True, cFiles = 0, cDirs = 0, cOthers = 0) ],
3519 [ tdTestDirRead(sDirectory = self.oTestFiles.oManyDir.sPath),
3520 tdTestResultDirRead(fRc = True, cFiles = len(self.oTestFiles.oManyDir.aoChildren), cDirs = 0, cOthers = 0) ],
3521 [ tdTestDirRead(sDirectory = self.oTestFiles.oTreeDir.sPath),
3522 tdTestResultDirRead(fRc = True, cFiles = self.oTestFiles.cTreeFiles, cDirs = self.oTestFiles.cTreeDirs,
3523 cOthers = self.oTestFiles.cTreeOthers) ],
3524 ]);
3525
3526
3527 fRc = True;
3528 for (i, tTest) in enumerate(atTests):
3529 oCurTest = tTest[0] # type: tdTestExec
3530 oCurRes = tTest[1] # type: tdTestResultDirRead
3531
3532 reporter.log('Testing #%d, dir="%s" ...' % (i, oCurTest.sDirectory));
3533 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3534 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirRead: Test #%d' % (i,));
3535 if fRc is not True:
3536 break;
3537 (fRc2, cDirs, cFiles, cOthers) = self.gctrlReadDirTree(oCurTest, oCurGuestSession, oCurRes.fRc);
3538 fRc = oCurTest.closeSession() and fRc;
3539
3540 reporter.log2('Test #%d: Returned %d directories, %d files total' % (i, cDirs, cFiles));
3541 if fRc2 is oCurRes.fRc:
3542 if fRc2 is True:
3543 if oCurRes.cFiles is None:
3544 pass; # ignore
3545 elif oCurRes.cFiles >= 0 and cFiles != oCurRes.cFiles:
3546 fRc = reporter.error('Test #%d failed: Got %d files, expected %d' % (i, cFiles, oCurRes.cFiles));
3547 elif oCurRes.cFiles < 0 and cFiles < -oCurRes.cFiles:
3548 fRc = reporter.error('Test #%d failed: Got %d files, expected at least %d'
3549 % (i, cFiles, -oCurRes.cFiles));
3550 if oCurRes.cDirs is None:
3551 pass; # ignore
3552 elif oCurRes.cDirs >= 0 and cDirs != oCurRes.cDirs:
3553 fRc = reporter.error('Test #%d failed: Got %d directories, expected %d' % (i, cDirs, oCurRes.cDirs));
3554 elif oCurRes.cDirs < 0 and cDirs < -oCurRes.cDirs:
3555 fRc = reporter.error('Test #%d failed: Got %d directories, expected at least %d'
3556 % (i, cDirs, -oCurRes.cDirs));
3557 if oCurRes.cOthers is None:
3558 pass; # ignore
3559 elif oCurRes.cOthers >= 0 and cOthers != oCurRes.cOthers:
3560 fRc = reporter.error('Test #%d failed: Got %d other types, expected %d' % (i, cOthers, oCurRes.cOthers));
3561 elif oCurRes.cOthers < 0 and cOthers < -oCurRes.cOthers:
3562 fRc = reporter.error('Test #%d failed: Got %d other types, expected at least %d'
3563 % (i, cOthers, -oCurRes.cOthers));
3564
3565 else:
3566 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc));
3567
3568
3569 #
3570 # Go over a few directories in the test file set and compare names,
3571 # types and sizes rather than just the counts like we did above.
3572 #
3573 if fRc is True:
3574 oCurTest = tdTestDirRead();
3575 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3576 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirRead: gctrlReadDirTree2');
3577 if fRc is True:
3578 for oDir in (self.oTestFiles.oEmptyDir, self.oTestFiles.oManyDir, self.oTestFiles.oTreeDir):
3579 reporter.log('Checking "%s" ...' % (oDir.sPath,));
3580 fRc = self.gctrlReadDirTree2(oCurGuestSession, oDir) and fRc;
3581 fRc = oCurTest.closeSession() and fRc;
3582
3583 return (fRc, oTxsSession);
3584
3585
3586 def testGuestCtrlFileRemove(self, oSession, oTxsSession, oTestVm):
3587 """
3588 Tests removing guest files.
3589 """
3590
3591 #
3592 # Create a directory with a few files in it using TXS that we'll use for the initial tests.
3593 #
3594 asTestDirs = [
3595 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1'), # [0]
3596 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1', 'subdir-1'), # [1]
3597 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1', 'subdir-1', 'subsubdir-1'), # [2]
3598 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2'), # [3]
3599 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2', 'subdir-2'), # [4]
3600 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2', 'subdir-2', 'subsbudir-2'), # [5]
3601 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-3'), # [6]
3602 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-4'), # [7]
3603 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-5'), # [8]
3604 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-5', 'subdir-5'), # [9]
3605 ]
3606 asTestFiles = [
3607 oTestVm.pathJoin(asTestDirs[0], 'file-0'), # [0]
3608 oTestVm.pathJoin(asTestDirs[0], 'file-1'), # [1]
3609 oTestVm.pathJoin(asTestDirs[0], 'file-2'), # [2]
3610 oTestVm.pathJoin(asTestDirs[1], 'file-3'), # [3] - subdir-1
3611 oTestVm.pathJoin(asTestDirs[1], 'file-4'), # [4] - subdir-1
3612 oTestVm.pathJoin(asTestDirs[2], 'file-5'), # [5] - subsubdir-1
3613 oTestVm.pathJoin(asTestDirs[3], 'file-6'), # [6] - rmtestdir-2
3614 oTestVm.pathJoin(asTestDirs[4], 'file-7'), # [7] - subdir-2
3615 oTestVm.pathJoin(asTestDirs[5], 'file-8'), # [8] - subsubdir-2
3616 ];
3617 for sDir in asTestDirs:
3618 if oTxsSession.syncMkDir(sDir, 0o777) is not True:
3619 return reporter.error('Failed to create test dir "%s"!' % (sDir,));
3620 for sFile in asTestFiles:
3621 if oTxsSession.syncUploadString(sFile, sFile, 0o666) is not True:
3622 return reporter.error('Failed to create test file "%s"!' % (sFile,));
3623
3624 #
3625 # Tear down the directories and files.
3626 #
3627 aoTests = [
3628 # Negative tests first:
3629 tdTestRemoveFile(asTestDirs[0], fRcExpect = False),
3630 tdTestRemoveDir(asTestDirs[0], fRcExpect = False),
3631 tdTestRemoveDir(asTestFiles[0], fRcExpect = False),
3632 tdTestRemoveFile(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-file'), fRcExpect = False),
3633 tdTestRemoveDir(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir'), fRcExpect = False),
3634 tdTestRemoveFile(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir', 'no-file'), fRcExpect = False),
3635 tdTestRemoveDir(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir', 'no-subdir'), fRcExpect = False),
3636 tdTestRemoveTree(asTestDirs[0], afFlags = [], fRcExpect = False), # Only removes empty dirs, this isn't empty.
3637 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_None,], fRcExpect = False), # ditto
3638 # Empty paths:
3639 tdTestRemoveFile('', fRcExpect = False),
3640 tdTestRemoveDir('', fRcExpect = False),
3641 tdTestRemoveTree('', fRcExpect = False),
3642 # Now actually remove stuff:
3643 tdTestRemoveDir(asTestDirs[7], fRcExpect = True),
3644 tdTestRemoveFile(asTestDirs[6], fRcExpect = False),
3645 tdTestRemoveDir(asTestDirs[6], fRcExpect = True),
3646 tdTestRemoveFile(asTestFiles[0], fRcExpect = True),
3647 tdTestRemoveFile(asTestFiles[0], fRcExpect = False),
3648 # 17:
3649 tdTestRemoveTree(asTestDirs[8], fRcExpect = True), # Removes empty subdirs and leaves the dir itself.
3650 tdTestRemoveDir(asTestDirs[8], fRcExpect = True),
3651 tdTestRemoveTree(asTestDirs[3], fRcExpect = False), # Have subdirs & files,
3652 tdTestRemoveTree(asTestDirs[3], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentOnly,], fRcExpect = True),
3653 tdTestRemoveDir(asTestDirs[3], fRcExpect = True),
3654 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentAndDir,], fRcExpect = True),
3655 # No error if already delete (RTDirRemoveRecursive artifact).
3656 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentAndDir,], fRcExpect = True),
3657 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentOnly,],
3658 fNotExist = True, fRcExpect = True),
3659 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_None,], fNotExist = True, fRcExpect = True),
3660 ];
3661
3662 #
3663 # Execution loop
3664 #
3665 fRc = True;
3666 for (i, oTest) in enumerate(aoTests): # int, tdTestRemoveBase
3667 reporter.log('Testing #%d, path="%s" %s ...' % (i, oTest.sPath, oTest.__class__.__name__));
3668 oTest.setEnvironment(oSession, oTxsSession, oTestVm);
3669 fRc, _ = oTest.createSession('testGuestCtrlFileRemove: Test #%d' % (i,));
3670 if fRc is False:
3671 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
3672 break;
3673 fRc = oTest.execute(self) and fRc;
3674 fRc = oTest.closeSession() and fRc;
3675
3676 if fRc is True:
3677 oCurTest = tdTestDirRead();
3678 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3679 fRc, oCurGuestSession = oCurTest.createSession('remove final');
3680 if fRc is True:
3681
3682 #
3683 # Delete all the files in the many subdir of the test set.
3684 #
3685 reporter.log('Deleting the file in "%s" ...' % (self.oTestFiles.oManyDir.sPath,));
3686 for oFile in self.oTestFiles.oManyDir.aoChildren:
3687 reporter.log2('"%s"' % (limitString(oFile.sPath),));
3688 try:
3689 if self.oTstDrv.fpApiVer >= 5.0:
3690 oCurGuestSession.fsObjRemove(oFile.sPath);
3691 else:
3692 oCurGuestSession.fileRemove(oFile.sPath);
3693 except:
3694 fRc = reporter.errorXcpt('Removing "%s" failed' % (oFile.sPath,));
3695
3696 # Remove the directory itself to verify that we've removed all the files in it:
3697 reporter.log('Removing the directory "%s" ...' % (self.oTestFiles.oManyDir.sPath,));
3698 try:
3699 oCurGuestSession.directoryRemove(self.oTestFiles.oManyDir.sPath);
3700 except:
3701 fRc = reporter.errorXcpt('Removing directory "%s" failed' % (self.oTestFiles.oManyDir.sPath,));
3702
3703 #
3704 # Recursively delete the entire test file tree from the root up.
3705 #
3706 # Note! On unix we cannot delete the root dir itself since it is residing
3707 # in /var/tmp where only the owner may delete it. Root is the owner.
3708 #
3709 if oTestVm.isWindows() or oTestVm.isOS2():
3710 afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentAndDir,];
3711 else:
3712 afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentOnly,];
3713 try:
3714 oProgress = oCurGuestSession.directoryRemoveRecursive(self.oTestFiles.oRoot.sPath, afFlags);
3715 except:
3716 fRc = reporter.errorXcpt('Removing tree "%s" failed' % (self.oTestFiles.oRoot.sPath,));
3717 else:
3718 oWrappedProgress = vboxwrappers.ProgressWrapper(oProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv,
3719 "remove-tree-root: %s" % (self.oTestFiles.oRoot.sPath,));
3720 reporter.log2('waiting ...')
3721 oWrappedProgress.wait();
3722 reporter.log2('isSuccess=%s' % (oWrappedProgress.isSuccess(),));
3723 if not oWrappedProgress.isSuccess():
3724 fRc = oWrappedProgress.logResult();
3725
3726 fRc = oCurTest.closeSession() and fRc;
3727
3728 return (fRc, oTxsSession);
3729
3730
3731 def testGuestCtrlFileStat(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
3732 """
3733 Tests querying file information through stat.
3734 """
3735
3736 # Basic stuff, existing stuff.
3737 aoTests = [
3738 tdTestSessionEx([
3739 tdStepStatDir('.'),
3740 tdStepStatDir('..'),
3741 tdStepStatDir(self.oTstDrv.getGuestTempDir(oTestVm)),
3742 tdStepStatDir(self.oTstDrv.getGuestSystemDir(oTestVm)),
3743 tdStepStatDirEx(self.oTestFiles.oRoot),
3744 tdStepStatDirEx(self.oTestFiles.oEmptyDir),
3745 tdStepStatDirEx(self.oTestFiles.oTreeDir),
3746 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
3747 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
3748 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
3749 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
3750 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
3751 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
3752 tdStepStatFile(self.oTstDrv.getGuestSystemFileForReading(oTestVm)),
3753 tdStepStatFile(self.oTstDrv.getGuestSystemShell(oTestVm)),
3754 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
3755 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
3756 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
3757 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
3758 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
3759 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
3760 ]),
3761 ];
3762
3763 # None existing stuff.
3764 sSysDir = self.oTstDrv.getGuestSystemDir(oTestVm);
3765 sSep = oTestVm.pathSep();
3766 aoTests += [
3767 tdTestSessionEx([
3768 tdStepStatFileNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory')),
3769 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory') + sSep),
3770 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', '.')),
3771 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', 'NoSuchFileOrSubDirectory')),
3772 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', 'NoSuchFileOrSubDirectory') + sSep),
3773 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', 'NoSuchFileOrSubDirectory', '.')),
3774 #tdStepStatPathNotFound('N:\\'), # ASSUMES nothing mounted on N:!
3775 #tdStepStatPathNotFound('\\\\NoSuchUncServerName\\NoSuchShare'),
3776 ]),
3777 ];
3778 # Invalid parameter check.
3779 aoTests += [ tdTestSessionEx([ tdStepStat('', vbox.ComError.E_INVALIDARG), ]), ];
3780
3781 #
3782 # Execute the tests.
3783 #
3784 fRc, oTxsSession = tdTestSessionEx.executeListTestSessions(aoTests, self.oTstDrv, oSession, oTxsSession,
3785 oTestVm, 'FsStat');
3786 #
3787 # Test the full test file set.
3788 #
3789 if self.oTstDrv.fpApiVer < 5.0:
3790 return (fRc, oTxsSession);
3791
3792 oTest = tdTestGuestCtrlBase();
3793 oTest.setEnvironment(oSession, oTxsSession, oTestVm);
3794 fRc2, oGuestSession = oTest.createSession('FsStat on TestFileSet');
3795 if fRc2 is not True:
3796 return (False, oTxsSession);
3797
3798 for sPath in self.oTestFiles.dPaths:
3799 oFsObj = self.oTestFiles.dPaths[sPath];
3800 reporter.log2('testGuestCtrlFileStat: %s sPath=%s'
3801 % ('file' if isinstance(oFsObj, testfileset.TestFile) else 'dir ', limitString(oFsObj.sPath),));
3802
3803 # Query the information:
3804 try:
3805 oFsInfo = oGuestSession.fsObjQueryInfo(oFsObj.sPath, False);
3806 except:
3807 fRc = reporter.errorXcpt('sPath=%s type=%s: fsObjQueryInfo trouble!' % (oFsObj.sPath, type(oFsObj),));
3808 continue;
3809 if oFsInfo is None:
3810 fRc = reporter.error('sPath=%s type=%s: No info object returned!' % (oFsObj.sPath, type(oFsObj),));
3811 continue;
3812
3813 # Check attributes:
3814 try:
3815 eType = oFsInfo.type;
3816 cbObject = oFsInfo.objectSize;
3817 except:
3818 fRc = reporter.errorXcpt('sPath=%s type=%s: attribute access trouble!' % (oFsObj.sPath, type(oFsObj),));
3819 continue;
3820
3821 if isinstance(oFsObj, testfileset.TestFile):
3822 if eType != vboxcon.FsObjType_File:
3823 fRc = reporter.error('sPath=%s type=file: eType=%s, expected %s!'
3824 % (oFsObj.sPath, eType, vboxcon.FsObjType_File));
3825 if cbObject != oFsObj.cbContent:
3826 fRc = reporter.error('sPath=%s type=file: cbObject=%s, expected %s!'
3827 % (oFsObj.sPath, cbObject, oFsObj.cbContent));
3828 fFileExists = True;
3829 fDirExists = False;
3830 elif isinstance(oFsObj, testfileset.TestDir):
3831 if eType != vboxcon.FsObjType_Directory:
3832 fRc = reporter.error('sPath=%s type=dir: eType=%s, expected %s!'
3833 % (oFsObj.sPath, eType, vboxcon.FsObjType_Directory));
3834 fFileExists = False;
3835 fDirExists = True;
3836 else:
3837 fRc = reporter.error('sPath=%s type=%s: Unexpected oFsObj type!' % (oFsObj.sPath, type(oFsObj),));
3838 continue;
3839
3840 # Check the directoryExists and fileExists results too.
3841 try:
3842 fExistsResult = oGuestSession.fileExists(oFsObj.sPath, False);
3843 except:
3844 fRc = reporter.errorXcpt('sPath=%s type=%s: fileExists trouble!' % (oFsObj.sPath, type(oFsObj),));
3845 else:
3846 if fExistsResult != fFileExists:
3847 fRc = reporter.error('sPath=%s type=%s: fileExists returned %s, expected %s!'
3848 % (oFsObj.sPath, type(oFsObj), fExistsResult, fFileExists));
3849 try:
3850 fExistsResult = oGuestSession.directoryExists(oFsObj.sPath, False);
3851 except:
3852 fRc = reporter.errorXcpt('sPath=%s type=%s: directoryExists trouble!' % (oFsObj.sPath, type(oFsObj),));
3853 else:
3854 if fExistsResult != fDirExists:
3855 fRc = reporter.error('sPath=%s type=%s: directoryExists returned %s, expected %s!'
3856 % (oFsObj.sPath, type(oFsObj), fExistsResult, fDirExists));
3857
3858 fRc = oTest.closeSession() and fRc;
3859 return (fRc, oTxsSession);
3860
3861 def testGuestCtrlFileOpen(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
3862 """
3863 Tests opening guest files.
3864 """
3865 if self.oTstDrv.fpApiVer < 5.0:
3866 reporter.log('Skipping because of pre 5.0 API');
3867 return None;
3868
3869 #
3870 # Paths.
3871 #
3872 sTempDir = self.oTstDrv.getGuestTempDir(oTestVm);
3873 sFileForReading = self.oTstDrv.getGuestSystemFileForReading(oTestVm);
3874 asFiles = [
3875 oTestVm.pathJoin(sTempDir, 'file-open-0'),
3876 oTestVm.pathJoin(sTempDir, 'file-open-1'),
3877 oTestVm.pathJoin(sTempDir, 'file-open-2'),
3878 oTestVm.pathJoin(sTempDir, 'file-open-3'),
3879 oTestVm.pathJoin(sTempDir, 'file-open-4'),
3880 ];
3881 asNonEmptyFiles = [
3882 oTestVm.pathJoin(sTempDir, 'file-open-10'),
3883 oTestVm.pathJoin(sTempDir, 'file-open-11'),
3884 oTestVm.pathJoin(sTempDir, 'file-open-12'),
3885 oTestVm.pathJoin(sTempDir, 'file-open-13'),
3886 ];
3887 sContent = 'abcdefghijklmnopqrstuvwxyz0123456789';
3888 for sFile in asNonEmptyFiles:
3889 if oTxsSession.syncUploadString(sContent, sFile, 0o666) is not True:
3890 return reporter.error('Failed to create "%s" via TXS' % (sFile,));
3891
3892 #
3893 # The tests.
3894 #
3895 atTests = [
3896 # Invalid stuff.
3897 [ tdTestFileOpen(sFile = ''), tdTestResultFailure() ],
3898 # Wrong open mode.
3899 [ tdTestFileOpen(sFile = sFileForReading, eAccessMode = -1), tdTestResultFailure() ],
3900 # Wrong disposition.
3901 [ tdTestFileOpen(sFile = sFileForReading, eAction = -1), tdTestResultFailure() ],
3902 # Non-existing file or path.
3903 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir')), tdTestResultFailure() ],
3904 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir'),
3905 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultFailure() ],
3906 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir'),
3907 eAccessMode = vboxcon.FileAccessMode_WriteOnly,
3908 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultFailure() ],
3909 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir'),
3910 eAccessMode = vboxcon.FileAccessMode_ReadWrite,
3911 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultFailure() ],
3912 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-dir', 'no-such-file')), tdTestResultFailure() ],
3913 ];
3914 if self.oTstDrv.fpApiVer > 5.2: # Fixed since 6.0.
3915 atTests.extend([
3916 # Wrong type:
3917 [ tdTestFileOpen(sFile = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3918 [ tdTestFileOpen(sFile = self.oTstDrv.getGuestSystemDir(oTestVm)), tdTestResultFailure() ],
3919 ]);
3920 atTests.extend([
3921 # O_EXCL and such:
3922 [ tdTestFileOpen(sFile = sFileForReading, eAction = vboxcon.FileOpenAction_CreateNew,
3923 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultFailure() ],
3924 [ tdTestFileOpen(sFile = sFileForReading, eAction = vboxcon.FileOpenAction_CreateNew), tdTestResultFailure() ],
3925 # Open a file.
3926 [ tdTestFileOpen(sFile = sFileForReading), tdTestResultSuccess() ],
3927 [ tdTestFileOpen(sFile = sFileForReading,
3928 eAction = vboxcon.FileOpenAction_OpenOrCreate), tdTestResultSuccess() ],
3929 # Create a new file.
3930 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_CreateNew,
3931 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3932 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_CreateNew,
3933 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultFailure() ],
3934 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_OpenExisting,
3935 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3936 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_CreateOrReplace,
3937 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3938 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_OpenOrCreate,
3939 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3940 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_OpenExistingTruncated,
3941 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3942 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_AppendOrCreate,
3943 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3944 # Open or create a new file.
3945 [ tdTestFileOpenCheckSize(sFile = asFiles[1], eAction = vboxcon.FileOpenAction_OpenOrCreate,
3946 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3947 # Create or replace a new file.
3948 [ tdTestFileOpenCheckSize(sFile = asFiles[2], eAction = vboxcon.FileOpenAction_CreateOrReplace,
3949 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3950 # Create and append to file (weird stuff).
3951 [ tdTestFileOpenCheckSize(sFile = asFiles[3], eAction = vboxcon.FileOpenAction_AppendOrCreate,
3952 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3953 [ tdTestFileOpenCheckSize(sFile = asFiles[4], eAction = vboxcon.FileOpenAction_AppendOrCreate,
3954 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
3955 # Open the non-empty files in non-destructive modes.
3956 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], cbOpenExpected = len(sContent)), tdTestResultSuccess() ],
3957 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], cbOpenExpected = len(sContent),
3958 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3959 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], cbOpenExpected = len(sContent),
3960 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
3961
3962 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], cbOpenExpected = len(sContent),
3963 eAction = vboxcon.FileOpenAction_OpenOrCreate,
3964 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3965 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], cbOpenExpected = len(sContent),
3966 eAction = vboxcon.FileOpenAction_OpenOrCreate,
3967 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
3968 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], cbOpenExpected = len(sContent),
3969 eAction = vboxcon.FileOpenAction_OpenOrCreate,
3970 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
3971
3972 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], cbOpenExpected = len(sContent),
3973 eAction = vboxcon.FileOpenAction_AppendOrCreate,
3974 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3975 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], cbOpenExpected = len(sContent),
3976 eAction = vboxcon.FileOpenAction_AppendOrCreate,
3977 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
3978 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], cbOpenExpected = len(sContent),
3979 eAction = vboxcon.FileOpenAction_AppendOrCreate,
3980 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
3981
3982 # Now the destructive stuff:
3983 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], eAccessMode = vboxcon.FileAccessMode_WriteOnly,
3984 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultSuccess() ],
3985 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], eAccessMode = vboxcon.FileAccessMode_WriteOnly,
3986 eAction = vboxcon.FileOpenAction_CreateOrReplace), tdTestResultSuccess() ],
3987 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], eAction = vboxcon.FileOpenAction_CreateOrReplace,
3988 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
3989 ]);
3990
3991 #
3992 # Do the testing.
3993 #
3994 fRc = True;
3995 for (i, tTest) in enumerate(atTests):
3996 oCurTest = tTest[0] # type: tdTestFileOpen
3997 oCurRes = tTest[1] # type: tdTestResult
3998
3999 reporter.log('Testing #%d: %s - sFile="%s", eAccessMode=%d, eAction=%d, (%s, %s, %s) ...'
4000 % (i, oCurTest.__class__.__name__, oCurTest.sFile, oCurTest.eAccessMode, oCurTest.eAction,
4001 oCurTest.eSharing, oCurTest.fCreationMode, oCurTest.afOpenFlags,));
4002
4003 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4004 fRc, _ = oCurTest.createSession('testGuestCtrlFileOpen: Test #%d' % (i,));
4005 if fRc is not True:
4006 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4007 break;
4008
4009 fRc2 = oCurTest.doSteps(oCurRes.fRc, self);
4010 if fRc2 != oCurRes.fRc:
4011 fRc = reporter.error('Test #%d result mismatch: Got %s, expected %s' % (i, fRc2, oCurRes.fRc,));
4012
4013 fRc = oCurTest.closeSession() and fRc;
4014
4015 return (fRc, oTxsSession);
4016
4017
4018 def testGuestCtrlFileRead(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-branches,too-many-statements
4019 """
4020 Tests reading from guest files.
4021 """
4022 if self.oTstDrv.fpApiVer < 5.0:
4023 reporter.log('Skipping because of pre 5.0 API');
4024 return None;
4025
4026 #
4027 # Do everything in one session.
4028 #
4029 oTest = tdTestGuestCtrlBase();
4030 oTest.setEnvironment(oSession, oTxsSession, oTestVm);
4031 fRc2, oGuestSession = oTest.createSession('FsStat on TestFileSet');
4032 if fRc2 is not True:
4033 return (False, oTxsSession);
4034
4035 #
4036 # Create a really big zero filled, up to 1 GiB, adding it to the list of
4037 # files from the set.
4038 #
4039 # Note! This code sucks a bit because we don't have a working setSize nor
4040 # any way to figure out how much free space there is in the guest.
4041 #
4042 aoExtraFiles = [];
4043 sBigName = self.oTestFiles.generateFilenameEx();
4044 sBigPath = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, sBigName);
4045 fRc = True;
4046 try:
4047 oFile = oGuestSession.fileOpenEx(sBigPath, vboxcon.FileAccessMode_ReadWrite, vboxcon.FileOpenAction_CreateOrReplace,
4048 vboxcon.FileSharingMode_All, 0, []);
4049 except:
4050 fRc = reporter.errorXcpt('sBigName=%s' % (sBigPath,));
4051 else:
4052 # Does setSize work now?
4053 fUseFallback = True;
4054 try:
4055 oFile.setSize(0);
4056 oFile.setSize(64);
4057 fUseFallback = False;
4058 except Exception as oXcpt:
4059 reporter.logXcpt();
4060
4061 # Grow the file till we hit trouble, typical VERR_DISK_FULL, then
4062 # reduce the file size if we have a working setSize.
4063 cbBigFile = 0;
4064 while cbBigFile < (1024 + 32)*1024*1024:
4065 if not fUseFallback:
4066 cbBigFile += 16*1024*1024;
4067 try:
4068 oFile.setSize(cbBigFile);
4069 except Exception as oXcpt:
4070 reporter.logXcpt('cbBigFile=%s' % (sBigPath,));
4071 try:
4072 cbBigFile -= 16*1024*1024;
4073 oFile.setSize(cbBigFile);
4074 except:
4075 reporter.logXcpt('cbBigFile=%s' % (sBigPath,));
4076 break;
4077 else:
4078 cbBigFile += 32*1024*1024;
4079 try:
4080 oFile.seek(cbBigFile, vboxcon.FileSeekOrigin_Begin);
4081 oFile.write(bytearray(1), 60*1000);
4082 except:
4083 reporter.logXcpt('cbBigFile=%s' % (sBigPath,));
4084 break;
4085 try:
4086 cbBigFile = oFile.seek(0, vboxcon.FileSeekOrigin_End);
4087 except:
4088 fRc = reporter.errorXcpt('sBigName=%s' % (sBigPath,));
4089 try:
4090 oFile.close();
4091 except:
4092 fRc = reporter.errorXcpt('sBigName=%s' % (sBigPath,));
4093 if fRc is True:
4094 reporter.log('Big file: %s bytes: %s' % (cbBigFile, sBigPath,));
4095 aoExtraFiles.append(testfileset.TestFileZeroFilled(None, sBigPath, cbBigFile));
4096 else:
4097 try:
4098 oGuestSession.fsObjRemove(sBigPath);
4099 except:
4100 reporter.errorXcpt('fsObjRemove(sBigName=%s)' % (sBigPath,));
4101
4102 #
4103 # Open and read all the files in the test file set.
4104 #
4105 for oTestFile in aoExtraFiles + self.oTestFiles.aoFiles: # type: testfileset.TestFile
4106 reporter.log2('Test file: %s bytes, "%s" ...' % (oTestFile.cbContent, limitString(oTestFile.sPath),));
4107
4108 #
4109 # Open it:
4110 #
4111 try:
4112 oFile = oGuestSession.fileOpenEx(oTestFile.sPath, vboxcon.FileAccessMode_ReadOnly,
4113 vboxcon.FileOpenAction_OpenExisting, vboxcon.FileSharingMode_All, 0, []);
4114 except:
4115 fRc = reporter.errorXcpt('sPath=%s' % (oTestFile.sPath, ));
4116 continue;
4117
4118 #
4119 # Read the file in different sized chunks:
4120 #
4121 if oTestFile.cbContent < 128:
4122 acbChunks = xrange(1,128);
4123 elif oTestFile.cbContent < 1024:
4124 acbChunks = (2048, 127, 63, 32, 29, 17, 16, 15, 9);
4125 elif oTestFile.cbContent < 8*1024*1024:
4126 acbChunks = (128*1024, 32*1024, 8191, 255);
4127 else:
4128 acbChunks = (768*1024, 128*1024);
4129
4130 for cbChunk in acbChunks:
4131 # Read the whole file straight thru:
4132 #if oTestFile.cbContent >= 1024*1024: reporter.log2('... cbChunk=%s' % (cbChunk,));
4133 offFile = 0;
4134 cReads = 0;
4135 while offFile <= oTestFile.cbContent:
4136 try:
4137 abRead = oFile.read(cbChunk, 30*1000);
4138 except:
4139 fRc = reporter.errorXcpt('%s: offFile=%s cbChunk=%s cbContent=%s'
4140 % (oTestFile.sPath, offFile, cbChunk, oTestFile.cbContent));
4141 break;
4142 cbRead = len(abRead);
4143 if cbRead == 0 and offFile == oTestFile.cbContent:
4144 break;
4145 if cbRead <= 0:
4146 fRc = reporter.error('%s @%s: cbRead=%s, cbContent=%s'
4147 % (oTestFile.sPath, offFile, cbRead, oTestFile.cbContent));
4148 break;
4149 if not oTestFile.equalMemory(abRead, offFile):
4150 fRc = reporter.error('%s: read mismatch @ %s LB %s' % (oTestFile.sPath, offFile, cbRead));
4151 break;
4152 offFile += cbRead;
4153 cReads += 1;
4154 if cReads > 8192:
4155 break;
4156
4157 # Seek to start of file.
4158 try:
4159 offFile = oFile.seek(0, vboxcon.FileSeekOrigin_Begin);
4160 except:
4161 fRc = reporter.errorXcpt('%s: error seeking to start of file' % (oTestFile.sPath,));
4162 break;
4163 if offFile != 0:
4164 fRc = reporter.error('%s: seek to start of file returned %u, expected 0' % (oTestFile.sPath, offFile));
4165 break;
4166
4167 #
4168 # Random reads.
4169 #
4170 for _ in xrange(8):
4171 offFile = self.oTestFiles.oRandom.randrange(0, oTestFile.cbContent + 1024);
4172 cbToRead = self.oTestFiles.oRandom.randrange(1, min(oTestFile.cbContent + 256, 768*1024));
4173 #if oTestFile.cbContent >= 1024*1024: reporter.log2('... %s LB %s' % (offFile, cbToRead,));
4174
4175 try:
4176 offActual = oFile.seek(offFile, vboxcon.FileSeekOrigin_Begin);
4177 except:
4178 fRc = reporter.errorXcpt('%s: error seeking to %s' % (oTestFile.sPath, offFile));
4179 break;
4180 if offActual != offFile:
4181 fRc = reporter.error('%s: seek(%s,Begin) -> %s, expected %s'
4182 % (oTestFile.sPath, offFile, offActual, offFile));
4183 break;
4184
4185 try:
4186 abRead = oFile.read(cbToRead, 30*1000);
4187 except:
4188 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s'
4189 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4190 cbRead = 0;
4191 else:
4192 cbRead = len(abRead);
4193 if not oTestFile.equalMemory(abRead, offFile):
4194 fRc = reporter.error('%s: random read mismatch @ %s LB %s' % (oTestFile.sPath, offFile, cbRead,));
4195
4196 try:
4197 offActual = oFile.offset;
4198 except:
4199 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#1)'
4200 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4201 else:
4202 if offActual != offFile + cbRead:
4203 fRc = reporter.error('%s: IFile.offset is %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#1)'
4204 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4205 try:
4206 offActual = oFile.seek(0, vboxcon.FileSeekOrigin_Current);
4207 except:
4208 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#1)'
4209 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4210 else:
4211 if offActual != offFile + cbRead:
4212 fRc = reporter.error('%s: seek(0,cur) -> %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#1)'
4213 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4214
4215 #
4216 # Random reads using readAt.
4217 #
4218 for _ in xrange(12):
4219 offFile = self.oTestFiles.oRandom.randrange(0, oTestFile.cbContent + 1024);
4220 cbToRead = self.oTestFiles.oRandom.randrange(1, min(oTestFile.cbContent + 256, 768*1024));
4221 #if oTestFile.cbContent >= 1024*1024: reporter.log2('... %s LB %s (readAt)' % (offFile, cbToRead,));
4222
4223 try:
4224 abRead = oFile.readAt(offFile, cbToRead, 30*1000);
4225 except:
4226 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s'
4227 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4228 cbRead = 0;
4229 else:
4230 cbRead = len(abRead);
4231 if not oTestFile.equalMemory(abRead, offFile):
4232 fRc = reporter.error('%s: random readAt mismatch @ %s LB %s' % (oTestFile.sPath, offFile, cbRead,));
4233
4234 try:
4235 offActual = oFile.offset;
4236 except:
4237 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#2)'
4238 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4239 else:
4240 if offActual != offFile + cbRead:
4241 fRc = reporter.error('%s: IFile.offset is %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#2)'
4242 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4243
4244 try:
4245 offActual = oFile.seek(0, vboxcon.FileSeekOrigin_Current);
4246 except:
4247 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#2)'
4248 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4249 else:
4250 if offActual != offFile + cbRead:
4251 fRc = reporter.error('%s: seek(0,cur) -> %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#2)'
4252 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4253
4254 #
4255 # A few negative things.
4256 #
4257
4258 # Zero byte reads -> E_INVALIDARG.
4259 try:
4260 abRead = oFile.read(0, 30*1000);
4261 except Exception as oXcpt:
4262 if vbox.ComError.notEqual(oXcpt, vbox.ComError.E_INVALIDARG):
4263 fRc = reporter.errorXcpt('read(0,30s) did not raise E_INVALIDARG as expected!');
4264 else:
4265 fRc = reporter.error('read(0,30s) did not fail!');
4266
4267 try:
4268 abRead = oFile.readAt(0, 0, 30*1000);
4269 except Exception as oXcpt:
4270 if vbox.ComError.notEqual(oXcpt, vbox.ComError.E_INVALIDARG):
4271 fRc = reporter.errorXcpt('readAt(0,0,30s) did not raise E_INVALIDARG as expected!');
4272 else:
4273 fRc = reporter.error('readAt(0,0,30s) did not fail!');
4274
4275 # See what happens when we read 1GiB. We should get a max of 1MiB back.
4276 ## @todo Document this behaviour in VirtualBox.xidl.
4277 try:
4278 oFile.seek(0, vboxcon.FileSeekOrigin_Begin);
4279 except:
4280 fRc = reporter.error('seek(0)');
4281 try:
4282 abRead = oFile.read(1024*1024*1024, 30*1000);
4283 except:
4284 fRc = reporter.errorXcpt('read(1GiB,30s)');
4285 else:
4286 if len(abRead) != min(oTestFile.cbContent, 1024*1024):
4287 fRc = reporter.error('Expected read(1GiB,30s) to return %s bytes, got %s bytes instead'
4288 % (min(oTestFile.cbContent, 1024*1024), len(abRead),));
4289
4290 try:
4291 abRead = oFile.readAt(0, 1024*1024*1024, 30*1000);
4292 except:
4293 fRc = reporter.errorXcpt('readAt(0,1GiB,30s)');
4294 else:
4295 if len(abRead) != min(oTestFile.cbContent, 1024*1024):
4296 reporter.error('Expected readAt(0, 1GiB,30s) to return %s bytes, got %s bytes instead'
4297 % (min(oTestFile.cbContent, 1024*1024), len(abRead),));
4298
4299 #
4300 # Check stat info on the file as well as querySize.
4301 #
4302 if self.oTstDrv.fpApiVer > 5.2:
4303 try:
4304 oFsObjInfo = oFile.queryInfo();
4305 except:
4306 fRc = reporter.errorXcpt('%s: queryInfo()' % (oTestFile.sPath,));
4307 else:
4308 if oFsObjInfo is None:
4309 fRc = reporter.error('IGuestFile::queryInfo returned None');
4310 else:
4311 try:
4312 cbFile = oFsObjInfo.objectSize;
4313 except:
4314 fRc = reporter.errorXcpt();
4315 else:
4316 if cbFile != oTestFile.cbContent:
4317 fRc = reporter.error('%s: queryInfo returned incorrect file size: %s, expected %s'
4318 % (oTestFile.sPath, cbFile, oTestFile.cbContent));
4319
4320 try:
4321 cbFile = oFile.querySize();
4322 except:
4323 fRc = reporter.errorXcpt('%s: querySize()' % (oTestFile.sPath,));
4324 else:
4325 if cbFile != oTestFile.cbContent:
4326 fRc = reporter.error('%s: querySize returned incorrect file size: %s, expected %s'
4327 % (oTestFile.sPath, cbFile, oTestFile.cbContent));
4328
4329 #
4330 # Use seek to test the file size and do a few other end-relative seeks.
4331 #
4332 try:
4333 cbFile = oFile.seek(0, vboxcon.FileSeekOrigin_End);
4334 except:
4335 fRc = reporter.errorXcpt('%s: seek(0,End)' % (oTestFile.sPath,));
4336 else:
4337 if cbFile != oTestFile.cbContent:
4338 fRc = reporter.error('%s: seek(0,End) returned incorrect file size: %s, expected %s'
4339 % (oTestFile.sPath, cbFile, oTestFile.cbContent));
4340 if oTestFile.cbContent > 0:
4341 for _ in xrange(5):
4342 offSeek = self.oTestFiles.oRandom.randrange(oTestFile.cbContent + 1);
4343 try:
4344 offFile = oFile.seek(-offSeek, vboxcon.FileSeekOrigin_End);
4345 except:
4346 fRc = reporter.errorXcpt('%s: seek(%s,End)' % (oTestFile.sPath, -offSeek,));
4347 else:
4348 if offFile != oTestFile.cbContent - offSeek:
4349 fRc = reporter.error('%s: seek(%s,End) returned incorrect offset: %s, expected %s (cbContent=%s)'
4350 % (oTestFile.sPath, -offSeek, offSeek, oTestFile.cbContent - offSeek,
4351 oTestFile.cbContent,));
4352
4353 #
4354 # Close it and we're done with this file.
4355 #
4356 try:
4357 oFile.close();
4358 except:
4359 fRc = reporter.errorXcpt('%s: error closing the file' % (oTestFile.sPath,));
4360
4361 #
4362 # Clean up.
4363 #
4364 for oTestFile in aoExtraFiles:
4365 try:
4366 oGuestSession.fsObjRemove(sBigPath);
4367 except:
4368 fRc = reporter.errorXcpt('fsObjRemove(%s)' % (sBigPath,));
4369
4370 fRc = oTest.closeSession() and fRc;
4371
4372 return (fRc, oTxsSession);
4373
4374
4375 def testGuestCtrlFileWrite(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
4376 """
4377 Tests writing to guest files.
4378 """
4379 if self.oTstDrv.fpApiVer < 5.0:
4380 reporter.log('Skipping because of pre 5.0 API');
4381 return None;
4382
4383 #
4384 # The test file and its content.
4385 #
4386 sFile = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'gctrl-write-1');
4387 abContent = bytearray(0);
4388
4389 #
4390 # The tests.
4391 #
4392 def randBytes(cbHowMany):
4393 """ Returns an bytearray of random bytes. """
4394 return bytearray(self.oTestFiles.oRandom.getrandbits(8) for _ in xrange(cbHowMany));
4395
4396 aoTests = [
4397 # Write at end:
4398 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_CreateNew, abContent = abContent,
4399 atChunks = [(None, randBytes(1)), (None, randBytes(77)), (None, randBytes(98)),]),
4400 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 1+77+98), # 176
4401 # Appending:
4402 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_AppendOrCreate, abContent = abContent,
4403 atChunks = [(None, randBytes(255)), (None, randBytes(33)),]),
4404 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 176 + 255+33), # 464
4405 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_AppendOrCreate, abContent = abContent,
4406 atChunks = [(10, randBytes(44)),]),
4407 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 464 + 44), # 508
4408 # Write within existing:
4409 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_OpenExisting, abContent = abContent,
4410 atChunks = [(0, randBytes(1)), (50, randBytes(77)), (255, randBytes(199)),]),
4411 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 508),
4412 # Writing around and over the end:
4413 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent,
4414 atChunks = [(500, randBytes(9)), (508, randBytes(15)), (512, randBytes(12)),]),
4415 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 512+12),
4416
4417 # writeAt appending:
4418 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True,
4419 atChunks = [(0, randBytes(23)), (6, randBytes(1018)),]),
4420 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 6+1018), # 1024
4421 # writeAt within existing:
4422 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True,
4423 atChunks = [(1000, randBytes(23)), (1, randBytes(990)),]),
4424 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 1024),
4425 # writeAt around and over the end:
4426 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True,
4427 atChunks = [(1024, randBytes(63)), (1080, randBytes(968)),]),
4428 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 1080+968), # 2048
4429
4430 # writeAt beyond the end (gap is filled with zeros):
4431 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True, atChunks = [(3070, randBytes(2)),]),
4432 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 3072),
4433 # write beyond the end (gap is filled with zeros):
4434 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, atChunks = [(4090, randBytes(6)),]),
4435 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 4096),
4436 ];
4437
4438 for (i, oCurTest) in enumerate(aoTests):
4439 reporter.log('Testing #%d: %s ...' % (i, oCurTest.toString(),));
4440
4441 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4442 fRc, _ = oCurTest.createSession('testGuestCtrlFileWrite: Test #%d' % (i,));
4443 if fRc is not True:
4444 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4445 break;
4446
4447 fRc2 = oCurTest.doSteps(True, self);
4448 if fRc2 is not True:
4449 fRc = reporter.error('Test #%d failed!' % (i,));
4450
4451 fRc = oCurTest.closeSession() and fRc;
4452
4453 #
4454 # Cleanup
4455 #
4456 if oTxsSession.syncRmFile(sFile) is not True:
4457 fRc = reporter.error('Failed to remove write-test file: %s' % (sFile, ));
4458
4459 return (fRc, oTxsSession);
4460
4461 @staticmethod
4462 def __generateFile(sName, cbFile):
4463 """ Helper for generating a file with a given size. """
4464 oFile = open(sName, 'wb');
4465 while cbFile > 0:
4466 cb = cbFile if cbFile < 256*1024 else 256*1024;
4467 oFile.write(bytearray(random.getrandbits(8) for _ in xrange(cb)));
4468 cbFile -= cb;
4469 oFile.close();
4470
4471 def testGuestCtrlCopyTo(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
4472 """
4473 Tests copying files from host to the guest.
4474 """
4475
4476 #
4477 # Paths and test files.
4478 #
4479 sScratchHst = os.path.join(self.oTstDrv.sScratchPath, 'copyto');
4480 sScratchTestFilesHst = os.path.join(sScratchHst, self.oTestFiles.sSubDir);
4481 sScratchEmptyDirHst = os.path.join(sScratchTestFilesHst, self.oTestFiles.oEmptyDir.sName);
4482 sScratchNonEmptyDirHst = self.oTestFiles.chooseRandomDirFromTree().buildPath(sScratchHst, os.path.sep);
4483 sScratchTreeDirHst = os.path.join(sScratchTestFilesHst, self.oTestFiles.oTreeDir.sName);
4484
4485 sScratchGst = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'copyto');
4486 sScratchDstDir1Gst = oTestVm.pathJoin(sScratchGst, 'dstdir1');
4487 sScratchDstDir2Gst = oTestVm.pathJoin(sScratchGst, 'dstdir2');
4488 sScratchDstDir3Gst = oTestVm.pathJoin(sScratchGst, 'dstdir3');
4489 sScratchDstDir4Gst = oTestVm.pathJoin(sScratchGst, 'dstdir4');
4490 #sScratchGstNotExist = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'no-such-file-or-directory');
4491 sScratchHstNotExist = os.path.join(self.oTstDrv.sScratchPath, 'no-such-file-or-directory');
4492 sScratchGstPathNotFound = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'no-such-directory', 'or-file');
4493 #sScratchHstPathNotFound = os.path.join(self.oTstDrv.sScratchPath, 'no-such-directory', 'or-file');
4494
4495 if oTestVm.isWindows() or oTestVm.isOS2():
4496 sScratchGstInvalid = "?*|<invalid-name>";
4497 else:
4498 sScratchGstInvalid = None;
4499 if utils.getHostOs() in ('win', 'os2'):
4500 sScratchHstInvalid = "?*|<invalid-name>";
4501 else:
4502 sScratchHstInvalid = None;
4503
4504 for sDir in (sScratchGst, sScratchDstDir1Gst, sScratchDstDir2Gst, sScratchDstDir3Gst, sScratchDstDir4Gst):
4505 if oTxsSession.syncMkDir(sDir, 0o777) is not True:
4506 return reporter.error('TXS failed to create directory "%s"!' % (sDir,));
4507
4508 # Put the test file set under sScratchHst.
4509 if os.path.exists(sScratchHst):
4510 if base.wipeDirectory(sScratchHst) != 0:
4511 return reporter.error('Failed to wipe "%s"' % (sScratchHst,));
4512 else:
4513 try:
4514 os.mkdir(sScratchHst);
4515 except:
4516 return reporter.errorXcpt('os.mkdir(%s)' % (sScratchHst, ));
4517 if self.oTestFiles.writeToDisk(sScratchHst) is not True:
4518 return reporter.error('Filed to write test files to "%s" on the host!' % (sScratchHst,));
4519
4520 # Generate a test file in 32MB to 64 MB range.
4521 sBigFileHst = os.path.join(self.oTstDrv.sScratchPath, 'gctrl-random.data');
4522 cbBigFileHst = random.randrange(32*1024*1024, 64*1024*1024);
4523 reporter.log('cbBigFileHst=%s' % (cbBigFileHst,));
4524 cbLeft = cbBigFileHst;
4525 try:
4526 self.__generateFile(sBigFileHst, cbBigFileHst);
4527 except:
4528 return reporter.errorXcpt('sBigFileHst=%s cbBigFileHst=%s cbLeft=%s' % (sBigFileHst, cbBigFileHst, cbLeft,));
4529 reporter.log('cbBigFileHst=%s' % (cbBigFileHst,));
4530
4531 # Generate an empty file on the host that we can use to save space in the guest.
4532 sEmptyFileHst = os.path.join(self.oTstDrv.sScratchPath, 'gctrl-empty.data');
4533 try:
4534 oFile = open(sEmptyFileHst, "wb");
4535 oFile.close();
4536 except:
4537 return reporter.errorXcpt('sEmptyFileHst=%s' % (sEmptyFileHst,));
4538
4539 #
4540 # Tests.
4541 #
4542 atTests = [
4543 # Nothing given:
4544 [ tdTestCopyToFile(), tdTestResultFailure() ],
4545 [ tdTestCopyToDir(), tdTestResultFailure() ],
4546 # Only source given:
4547 [ tdTestCopyToFile(sSrc = sBigFileHst), tdTestResultFailure() ],
4548 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst), tdTestResultFailure() ],
4549 # Only destination given:
4550 [ tdTestCopyToFile(sDst = oTestVm.pathJoin(sScratchGst, 'dstfile')), tdTestResultFailure() ],
4551 [ tdTestCopyToDir( sDst = sScratchGst), tdTestResultFailure() ],
4552 # Both given, but invalid flags.
4553 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGst, afFlags = [ 0x40000000] ), tdTestResultFailure() ],
4554 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst, sDst = sScratchGst, afFlags = [ 0x40000000] ),
4555 tdTestResultFailure() ],
4556 ];
4557 atTests.extend([
4558 # Non-existing source, but no destination:
4559 [ tdTestCopyToFile(sSrc = sScratchHstNotExist), tdTestResultFailure() ],
4560 [ tdTestCopyToDir( sSrc = sScratchHstNotExist), tdTestResultFailure() ],
4561 # Valid sources, but destination path not found:
4562 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGstPathNotFound), tdTestResultFailure() ],
4563 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst, sDst = sScratchGstPathNotFound), tdTestResultFailure() ],
4564 # Valid destination, but source file/dir not found:
4565 [ tdTestCopyToFile(sSrc = sScratchHstNotExist, sDst = oTestVm.pathJoin(sScratchGst, 'dstfile')),
4566 tdTestResultFailure() ],
4567 [ tdTestCopyToDir( sSrc = sScratchHstNotExist, sDst = sScratchGst), tdTestResultFailure() ],
4568 # Wrong type:
4569 [ tdTestCopyToFile(sSrc = sScratchEmptyDirHst, sDst = oTestVm.pathJoin(sScratchGst, 'dstfile')),
4570 tdTestResultFailure() ],
4571 [ tdTestCopyToDir( sSrc = sBigFileHst, sDst = sScratchGst), tdTestResultFailure() ],
4572 ]);
4573 # Invalid characters in destination or source path:
4574 if sScratchGstInvalid is not None:
4575 atTests.extend([
4576 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, sScratchGstInvalid)),
4577 tdTestResultFailure() ],
4578 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst, sDst = oTestVm.pathJoin(sScratchGst, sScratchGstInvalid)),
4579 tdTestResultFailure() ],
4580 ]);
4581 if sScratchHstInvalid is not None:
4582 atTests.extend([
4583 [ tdTestCopyToFile(sSrc = os.path.join(self.oTstDrv.sScratchPath, sScratchHstInvalid), sDst = sScratchGst),
4584 tdTestResultFailure() ],
4585 [ tdTestCopyToDir( sSrc = os.path.join(self.oTstDrv.sScratchPath, sScratchHstInvalid), sDst = sScratchGst),
4586 tdTestResultFailure() ],
4587 ]);
4588
4589 #
4590 # Single file handling.
4591 #
4592 atTests.extend([
4593 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat')),
4594 tdTestResultSuccess() ],
4595 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat')), # Overwrite
4596 tdTestResultSuccess() ],
4597 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat')), # Overwrite
4598 tdTestResultSuccess() ],
4599 ]);
4600 if self.oTstDrv.fpApiVer > 5.2: # Copying files into directories via Main is supported only 6.0 and later.
4601 atTests.extend([
4602 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGst), tdTestResultSuccess() ],
4603 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGst), tdTestResultSuccess() ], # Overwrite
4604 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = oTestVm.pathJoin(sScratchGst, os.path.split(sBigFileHst)[1])),
4605 tdTestResultSuccess() ], # Overwrite
4606 ]);
4607
4608 if oTestVm.isWindows():
4609 # Copy to a Windows alternative data stream (ADS).
4610 atTests.extend([
4611 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat:ADS-Test')),
4612 tdTestResultSuccess() ],
4613 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat:ADS-Test')),
4614 tdTestResultSuccess() ],
4615 ]);
4616
4617 #
4618 # Directory handling.
4619 #
4620 if self.oTstDrv.fpApiVer > 5.2: # Copying directories via Main is supported only in versions > 5.2.
4621 atTests.extend([
4622 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir1Gst,
4623 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4624 # Try again.
4625 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir1Gst,
4626 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4627 # Should fail, as destination directory already exists.
4628 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir1Gst), tdTestResultFailure() ],
4629 # Try again with trailing slash, should yield the same result:
4630 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir2Gst + oTestVm.pathSep(),
4631 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4632 # Try again.
4633 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir2Gst + oTestVm.pathSep(),
4634 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4635 # Should fail, as destination directory already exists.
4636 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir2Gst + oTestVm.pathSep()),
4637 tdTestResultFailure() ],
4638 # Copy with a different destination name just for the heck of it:
4639 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = oTestVm.pathJoin(sScratchDstDir1Gst, 'empty2')),
4640 tdTestResultSuccess() ],
4641 ]);
4642 atTests.extend([
4643 # Now the same using a directory with files in it:
4644 [ tdTestCopyToDir(sSrc = sScratchNonEmptyDirHst, sDst = sScratchDstDir3Gst,
4645 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4646 # Again.
4647 [ tdTestCopyToDir(sSrc = sScratchNonEmptyDirHst, sDst = sScratchDstDir3Gst,
4648 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4649 # Should fail, as directory is existing already.
4650 [ tdTestCopyToDir(sSrc = sScratchNonEmptyDirHst, sDst = sScratchDstDir3Gst), tdTestResultFailure() ],
4651 ]);
4652 atTests.extend([
4653 # Copy the entire test tree:
4654 [ tdTestCopyToDir(sSrc = sScratchTreeDirHst, sDst = sScratchDstDir4Gst,
4655 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4656 ]);
4657
4658 fRc = True;
4659 for (i, tTest) in enumerate(atTests):
4660 oCurTest = tTest[0]; # tdTestCopyTo
4661 oCurRes = tTest[1]; # tdTestResult
4662 reporter.log('Testing #%d, sSrc=%s, sDst=%s, afFlags=%s ...'
4663 % (i, limitString(oCurTest.sSrc), limitString(oCurTest.sDst), oCurTest.afFlags));
4664
4665 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4666 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlCopyTo: Test #%d' % (i,));
4667 if fRc is not True:
4668 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4669 break;
4670
4671 fRc2 = False;
4672 if isinstance(oCurTest, tdTestCopyToFile):
4673 fRc2 = self.gctrlCopyFileTo(oCurGuestSession, oCurTest.sSrc, oCurTest.sDst, oCurTest.afFlags, oCurRes.fRc);
4674 else:
4675 fRc2 = self.gctrlCopyDirTo(oCurGuestSession, oCurTest.sSrc, oCurTest.sDst, oCurTest.afFlags, oCurRes.fRc);
4676 if fRc2 is not oCurRes.fRc:
4677 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc));
4678
4679 fRc = oCurTest.closeSession() and fRc;
4680
4681 return (fRc, oTxsSession);
4682
4683 def testGuestCtrlCopyFrom(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
4684 """
4685 Tests copying files from guest to the host.
4686 """
4687
4688 #
4689 # Paths.
4690 #
4691 sScratchHst = os.path.join(self.oTstDrv.sScratchPath, "testGctrlCopyFrom");
4692 sScratchDstDir1Hst = os.path.join(sScratchHst, "dstdir1");
4693 sScratchDstDir2Hst = os.path.join(sScratchHst, "dstdir2");
4694 sScratchDstDir3Hst = os.path.join(sScratchHst, "dstdir3");
4695 oExistingFileGst = self.oTestFiles.chooseRandomFile();
4696 oNonEmptyDirGst = self.oTestFiles.chooseRandomDirFromTree(fNonEmpty = True);
4697 oEmptyDirGst = self.oTestFiles.oEmptyDir;
4698
4699 if oTestVm.isWindows() or oTestVm.isOS2():
4700 sScratchGstInvalid = "?*|<invalid-name>";
4701 else:
4702 sScratchGstInvalid = None;
4703 if utils.getHostOs() in ('win', 'os2'):
4704 sScratchHstInvalid = "?*|<invalid-name>";
4705 else:
4706 sScratchHstInvalid = None;
4707
4708 if os.path.exists(sScratchHst):
4709 if base.wipeDirectory(sScratchHst) != 0:
4710 return reporter.error('Failed to wipe "%s"' % (sScratchHst,));
4711 else:
4712 try:
4713 os.mkdir(sScratchHst);
4714 except:
4715 return reporter.errorXcpt('os.mkdir(%s)' % (sScratchHst, ));
4716
4717 for sSubDir in (sScratchDstDir1Hst, sScratchDstDir2Hst, sScratchDstDir3Hst):
4718 try:
4719 os.mkdir(sSubDir);
4720 except:
4721 return reporter.errorXcpt('os.mkdir(%s)' % (sSubDir, ));
4722
4723 #
4724 # Bad parameter tests.
4725 #
4726 atTests = [
4727 # Missing both source and destination:
4728 [ tdTestCopyFromFile(), tdTestResultFailure() ],
4729 [ tdTestCopyFromDir(), tdTestResultFailure() ],
4730 # Missing source.
4731 [ tdTestCopyFromFile(sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
4732 [ tdTestCopyFromDir( sDst = sScratchHst), tdTestResultFailure() ],
4733 # Missing destination.
4734 [ tdTestCopyFromFile(oSrc = oExistingFileGst), tdTestResultFailure() ],
4735 [ tdTestCopyFromDir( sSrc = self.oTestFiles.oManyDir.sPath), tdTestResultFailure() ],
4736 # Invalid flags:
4737 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'somefile'), afFlags = [0x40000000]),
4738 tdTestResultFailure() ],
4739 [ tdTestCopyFromDir( oSrc = oEmptyDirGst, sDst = os.path.join(sScratchHst, 'somedir'), afFlags = [ 0x40000000] ),
4740 tdTestResultFailure() ],
4741 # Non-existing sources:
4742 [ tdTestCopyFromFile(sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-file-or-directory'),
4743 sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
4744 [ tdTestCopyFromDir( sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-file-or-directory'),
4745 sDst = os.path.join(sScratchHst, 'somedir')), tdTestResultFailure() ],
4746 [ tdTestCopyFromFile(sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-directory', 'no-such-file'),
4747 sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
4748 [ tdTestCopyFromDir( sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-directory', 'no-such-subdir'),
4749 sDst = os.path.join(sScratchHst, 'somedir')), tdTestResultFailure() ],
4750 # Non-existing destinations:
4751 [ tdTestCopyFromFile(oSrc = oExistingFileGst,
4752 sDst = os.path.join(sScratchHst, 'no-such-directory', 'somefile') ), tdTestResultFailure() ],
4753 [ tdTestCopyFromDir( oSrc = oEmptyDirGst, sDst = os.path.join(sScratchHst, 'no-such-directory', 'somedir') ),
4754 tdTestResultFailure() ],
4755 [ tdTestCopyFromFile(oSrc = oExistingFileGst,
4756 sDst = os.path.join(sScratchHst, 'no-such-directory-slash' + os.path.sep)),
4757 tdTestResultFailure() ],
4758 # Wrong source type:
4759 [ tdTestCopyFromFile(oSrc = oNonEmptyDirGst, sDst = os.path.join(sScratchHst, 'somefile') ), tdTestResultFailure() ],
4760 [ tdTestCopyFromDir(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'somedir') ), tdTestResultFailure() ],
4761 ];
4762 # Bogus names:
4763 if sScratchHstInvalid:
4764 atTests.extend([
4765 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, sScratchHstInvalid)),
4766 tdTestResultFailure() ],
4767 [ tdTestCopyFromDir( sSrc = self.oTestFiles.oManyDir.sPath, sDst = os.path.join(sScratchHst, sScratchHstInvalid)),
4768 tdTestResultFailure() ],
4769 ]);
4770 if sScratchGstInvalid:
4771 atTests.extend([
4772 [ tdTestCopyFromFile(sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, sScratchGstInvalid),
4773 sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
4774 [ tdTestCopyFromDir( sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, sScratchGstInvalid),
4775 sDst = os.path.join(sScratchHst, 'somedir')), tdTestResultFailure() ],
4776 ]);
4777
4778 #
4779 # Single file copying.
4780 #
4781 atTests.extend([
4782 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'copyfile1')),
4783 tdTestResultSuccess() ],
4784 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'copyfile1')), # Overwrite it
4785 tdTestResultSuccess() ],
4786 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'copyfile2')),
4787 tdTestResultSuccess() ],
4788 ]);
4789 if self.oTstDrv.fpApiVer > 5.2:
4790 # Copy into a directory.
4791 atTests.extend([
4792 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = sScratchHst), tdTestResultSuccess() ],
4793 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = sScratchHst + os.path.sep), tdTestResultSuccess() ],
4794 ]);
4795
4796 #
4797 # Directory tree copying:
4798 #
4799 atTests.extend([
4800 # Copy the empty guest directory (should end up as sScratchHst/empty):
4801 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir1Hst), tdTestResultSuccess() ],
4802 # Repeat -- this time it should fail, as the destination directory already exists (and
4803 # DirectoryCopyFlag_CopyIntoExisting is not specified):
4804 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir1Hst), tdTestResultFailure() ],
4805 # Add the DirectoryCopyFlag_CopyIntoExisting flag being set and it should work.
4806 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir1Hst,
4807 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
4808 # Try again with trailing slash, should yield the same result:
4809 [ tdTestRemoveHostDir(os.path.join(sScratchDstDir1Hst, 'empty')), tdTestResult() ],
4810 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir1Hst + os.path.sep),
4811 tdTestResultSuccess() ],
4812 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir1Hst + os.path.sep),
4813 tdTestResultFailure() ],
4814 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir1Hst + os.path.sep,
4815 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
4816 # Copy with a different destination name just for the heck of it:
4817 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = os.path.join(sScratchHst, 'empty2'), fIntoDst = True),
4818 tdTestResultFailure() ],
4819 # Now the same using a directory with files in it:
4820 [ tdTestCopyFromDir(oSrc = oNonEmptyDirGst, sDst = sScratchDstDir2Hst), tdTestResultSuccess() ],
4821 [ tdTestCopyFromDir(oSrc = oNonEmptyDirGst, sDst = sScratchDstDir2Hst), tdTestResultFailure() ],
4822 [ tdTestCopyFromDir(oSrc = oNonEmptyDirGst, sDst = sScratchDstDir2Hst,
4823 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
4824 # Copy the entire test tree:
4825 [ tdTestCopyFromDir(sSrc = self.oTestFiles.oTreeDir.sPath, sDst = sScratchDstDir3Hst), tdTestResultSuccess() ],
4826 ]);
4827
4828 #
4829 # Execute the tests.
4830 #
4831 fRc = True;
4832 for (i, tTest) in enumerate(atTests):
4833 oCurTest = tTest[0]
4834 oCurRes = tTest[1] # type: tdTestResult
4835 if isinstance(oCurTest, tdTestCopyFrom):
4836 reporter.log('Testing #%d, %s: sSrc="%s", sDst="%s", afFlags="%s" ...'
4837 % (i, "directory" if isinstance(oCurTest, tdTestCopyFromDir) else "file",
4838 limitString(oCurTest.sSrc), limitString(oCurTest.sDst), oCurTest.afFlags,));
4839 else:
4840 reporter.log('Testing #%d, tdTestRemoveHostDir "%s" ...' % (i, oCurTest.sDir,));
4841 if isinstance(oCurTest, tdTestCopyFromDir) and self.oTstDrv.fpApiVer < 6.0:
4842 reporter.log('Skipping directoryCopyFromGuest test, not implemented in %s' % (self.oTstDrv.fpApiVer,));
4843 continue;
4844
4845 if isinstance(oCurTest, tdTestRemoveHostDir):
4846 fRc = oCurTest.execute(self.oTstDrv, oSession, oTxsSession, oTestVm, 'testing #%d' % (i,));
4847 else:
4848 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4849 fRc2, oCurGuestSession = oCurTest.createSession('testGuestCtrlCopyFrom: Test #%d' % (i,));
4850 if fRc2 is not True:
4851 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4852 break;
4853
4854 if isinstance(oCurTest, tdTestCopyFromFile):
4855 fRc2 = self.gctrlCopyFileFrom(oCurGuestSession, oCurTest, oCurRes.fRc);
4856 else:
4857 fRc2 = self.gctrlCopyDirFrom(oCurGuestSession, oCurTest, oCurRes.fRc);
4858
4859 if fRc2 != oCurRes.fRc:
4860 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc));
4861
4862 fRc = oCurTest.closeSession() and fRc;
4863
4864 return (fRc, oTxsSession);
4865
4866 def testGuestCtrlUpdateAdditions(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
4867 """
4868 Tests updating the Guest Additions inside the guest.
4869
4870 """
4871
4872 ## @todo currently disabled everywhere.
4873 if self.oTstDrv.fpApiVer < 100.0:
4874 reporter.log("Skipping updating GAs everywhere for now...");
4875 return None;
4876
4877 # Skip test for updating Guest Additions if we run on a too old (Windows) guest.
4878 ##
4879 ## @todo make it work everywhere!
4880 ##
4881 if oTestVm.sKind in ('WindowsNT4', 'Windows2000', 'WindowsXP', 'Windows2003'):
4882 reporter.log("Skipping updating GAs on old windows vm (sKind=%s)" % (oTestVm.sKind,));
4883 return (None, oTxsSession);
4884 if oTestVm.isOS2():
4885 reporter.log("Skipping updating GAs on OS/2 guest");
4886 return (None, oTxsSession);
4887
4888 sVBoxValidationKitIso = self.oTstDrv.sVBoxValidationKitIso;
4889 if not os.path.isfile(sVBoxValidationKitIso):
4890 return reporter.log('Validation Kit .ISO not found at "%s"' % (sVBoxValidationKitIso,));
4891
4892 sScratch = os.path.join(self.oTstDrv.sScratchPath, "testGctrlUpdateAdditions");
4893 try:
4894 os.makedirs(sScratch);
4895 except OSError as e:
4896 if e.errno != errno.EEXIST:
4897 return reporter.error('Failed: Unable to create scratch directory \"%s\"' % (sScratch,));
4898 reporter.log('Scratch path is: %s' % (sScratch,));
4899
4900 atTests = [];
4901 if oTestVm.isWindows():
4902 atTests.extend([
4903 # Source is missing.
4904 [ tdTestUpdateAdditions(sSrc = ''), tdTestResultFailure() ],
4905
4906 # Wrong flags.
4907 [ tdTestUpdateAdditions(sSrc = self.oTstDrv.getGuestAdditionsIso(),
4908 afFlags = [ 1234 ]), tdTestResultFailure() ],
4909
4910 # Non-existing .ISO.
4911 [ tdTestUpdateAdditions(sSrc = "non-existing.iso"), tdTestResultFailure() ],
4912
4913 # Wrong .ISO.
4914 [ tdTestUpdateAdditions(sSrc = sVBoxValidationKitIso), tdTestResultFailure() ],
4915
4916 # The real thing.
4917 [ tdTestUpdateAdditions(sSrc = self.oTstDrv.getGuestAdditionsIso()),
4918 tdTestResultSuccess() ],
4919 # Test the (optional) installer arguments. This will extract the
4920 # installer into our guest's scratch directory.
4921 [ tdTestUpdateAdditions(sSrc = self.oTstDrv.getGuestAdditionsIso(),
4922 asArgs = [ '/extract', '/D=' + sScratch ]),
4923 tdTestResultSuccess() ]
4924 # Some debg ISO. Only enable locally.
4925 #[ tdTestUpdateAdditions(
4926 # sSrc = "V:\\Downloads\\VBoxGuestAdditions-r80354.iso"),
4927 # tdTestResultSuccess() ]
4928 ]);
4929 else:
4930 reporter.log('No OS-specific tests for non-Windows yet!');
4931
4932 fRc = True;
4933 for (i, tTest) in enumerate(atTests):
4934 oCurTest = tTest[0] # type: tdTestUpdateAdditions
4935 oCurRes = tTest[1] # type: tdTestResult
4936 reporter.log('Testing #%d, sSrc="%s", afFlags="%s" ...' % (i, oCurTest.sSrc, oCurTest.afFlags,));
4937
4938 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4939 fRc, _ = oCurTest.createSession('Test #%d' % (i,));
4940 if fRc is not True:
4941 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4942 break;
4943
4944 try:
4945 oCurProgress = oCurTest.oGuest.updateGuestAdditions(oCurTest.sSrc, oCurTest.asArgs, oCurTest.afFlags);
4946 except:
4947 reporter.maybeErrXcpt(oCurRes.fRc, 'Updating Guest Additions exception for sSrc="%s", afFlags="%s":'
4948 % (oCurTest.sSrc, oCurTest.afFlags,));
4949 fRc = False;
4950 else:
4951 if oCurProgress is not None:
4952 oWrapperProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr,
4953 self.oTstDrv, "gctrlUpGA");
4954 oWrapperProgress.wait();
4955 if not oWrapperProgress.isSuccess():
4956 oWrapperProgress.logResult(fIgnoreErrors = not oCurRes.fRc);
4957 fRc = False;
4958 else:
4959 fRc = reporter.error('No progress object returned');
4960
4961 oCurTest.closeSession();
4962 if fRc is oCurRes.fRc:
4963 if fRc:
4964 ## @todo Verify if Guest Additions were really updated (build, revision, ...).
4965 ## @todo r=bird: Not possible since you're installing the same GAs as before...
4966 ## Maybe check creation dates on certain .sys/.dll/.exe files?
4967 pass;
4968 else:
4969 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc, oCurRes.fRc));
4970 break;
4971
4972 return (fRc, oTxsSession);
4973
4974
4975
4976class tdAddGuestCtrl(vbox.TestDriver): # pylint: disable=too-many-instance-attributes,too-many-public-methods
4977 """
4978 Guest control using VBoxService on the guest.
4979 """
4980
4981 def __init__(self):
4982 vbox.TestDriver.__init__(self);
4983 self.oTestVmSet = self.oTestVmManager.getSmokeVmSet('nat');
4984 self.asRsrcs = None;
4985 self.fQuick = False; # Don't skip lengthly tests by default.
4986 self.addSubTestDriver(SubTstDrvAddGuestCtrl(self));
4987
4988 #
4989 # Overridden methods.
4990 #
4991 def showUsage(self):
4992 """
4993 Shows the testdriver usage.
4994 """
4995 rc = vbox.TestDriver.showUsage(self);
4996 reporter.log('');
4997 reporter.log('tdAddGuestCtrl Options:');
4998 reporter.log(' --quick');
4999 reporter.log(' Same as --virt-modes hwvirt --cpu-counts 1.');
5000 return rc;
5001
5002 def parseOption(self, asArgs, iArg): # pylint: disable=too-many-branches,too-many-statements
5003 """
5004 Parses the testdriver arguments from the command line.
5005 """
5006 if asArgs[iArg] == '--quick':
5007 self.parseOption(['--virt-modes', 'hwvirt'], 0);
5008 self.parseOption(['--cpu-counts', '1'], 0);
5009 self.fQuick = True;
5010 else:
5011 return vbox.TestDriver.parseOption(self, asArgs, iArg);
5012 return iArg + 1;
5013
5014 def actionConfig(self):
5015 if not self.importVBoxApi(): # So we can use the constant below.
5016 return False;
5017
5018 eNic0AttachType = vboxcon.NetworkAttachmentType_NAT;
5019 sGaIso = self.getGuestAdditionsIso();
5020 return self.oTestVmSet.actionConfig(self, eNic0AttachType = eNic0AttachType, sDvdImage = sGaIso);
5021
5022 def actionExecute(self):
5023 return self.oTestVmSet.actionExecute(self, self.testOneCfg);
5024
5025 #
5026 # Test execution helpers.
5027 #
5028 def testOneCfg(self, oVM, oTestVm): # pylint: disable=too-many-statements
5029 """
5030 Runs the specified VM thru the tests.
5031
5032 Returns a success indicator on the general test execution. This is not
5033 the actual test result.
5034 """
5035
5036 self.logVmInfo(oVM);
5037
5038 fRc = True;
5039 oSession, oTxsSession = self.startVmAndConnectToTxsViaTcp(oTestVm.sVmName, fCdWait = False);
5040 reporter.log("TxsSession: %s" % (oTxsSession,));
5041 if oSession is not None:
5042 self.addTask(oTxsSession);
5043
5044 fRc, oTxsSession = self.aoSubTstDrvs[0].testIt(oTestVm, oSession, oTxsSession);
5045
5046 # Cleanup.
5047 self.removeTask(oTxsSession);
5048 if not self.aoSubTstDrvs[0].oDebug.fNoExit:
5049 self.terminateVmBySession(oSession);
5050 else:
5051 fRc = False;
5052 return fRc;
5053
5054 def onExit(self, iRc):
5055 if self.aoSubTstDrvs[0].oDebug.fNoExit:
5056 return True
5057 return vbox.TestDriver.onExit(self, iRc);
5058
5059 def gctrlReportError(self, progress):
5060 """
5061 Helper function to report an error of a
5062 given progress object.
5063 """
5064 if progress is None:
5065 reporter.log('No progress object to print error for');
5066 else:
5067 errInfo = progress.errorInfo;
5068 if errInfo:
5069 reporter.log('%s' % (errInfo.text,));
5070 return False;
5071
5072 def gctrlGetRemainingTime(self, msTimeout, msStart):
5073 """
5074 Helper function to return the remaining time (in ms)
5075 based from a timeout value and the start time (both in ms).
5076 """
5077 if msTimeout == 0:
5078 return 0xFFFFFFFE; # Wait forever.
5079 msElapsed = base.timestampMilli() - msStart;
5080 if msElapsed > msTimeout:
5081 return 0; # No time left.
5082 return msTimeout - msElapsed;
5083
5084 def testGuestCtrlManual(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals,too-many-statements,unused-argument,unused-variable
5085 """
5086 For manually testing certain bits.
5087 """
5088
5089 reporter.log('Manual testing ...');
5090 fRc = True;
5091
5092 sUser = 'Administrator';
5093 sPassword = 'password';
5094
5095 oGuest = oSession.o.console.guest;
5096 oGuestSession = oGuest.createSession(sUser,
5097 sPassword,
5098 "", "Manual Test");
5099
5100 aWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
5101 _ = oGuestSession.waitForArray(aWaitFor, 30 * 1000);
5102
5103 sCmd = self.getGuestSystemShell(oTestVm);
5104 asArgs = [ sCmd, '/C', 'dir', '/S', 'c:\\windows' ];
5105 aEnv = [];
5106 afFlags = [];
5107
5108 for _ in xrange(100):
5109 oProc = oGuestSession.processCreate(sCmd, asArgs if self.fpApiVer >= 5.0 else asArgs[1:],
5110 aEnv, afFlags, 30 * 1000);
5111
5112 aWaitFor = [ vboxcon.ProcessWaitForFlag_Terminate ];
5113 _ = oProc.waitForArray(aWaitFor, 30 * 1000);
5114
5115 oGuestSession.close();
5116 oGuestSession = None;
5117
5118 time.sleep(5);
5119
5120 oSession.o.console.PowerDown();
5121
5122 return (fRc, oTxsSession);
5123
5124if __name__ == '__main__':
5125 sys.exit(tdAddGuestCtrl().main(sys.argv));
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette