VirtualBox

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

Last change on this file since 84730 was 84730, checked in by vboxsync, 4 years ago

Validation Kit/tdAddGuestCtrl.py: Refined long arguments testing a bit.

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 248.4 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: 84730 $"
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, 'Manual 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 reporter.log('Skipping debugging');
1497 return True
1498
1499 reporter.log('Preparing for debugging ...');
1500
1501 try:
1502
1503 self.vboxServiceControl(oTxsSession, oTestVm, fStart = False);
1504
1505 if oTestVm.isLinux():
1506 reporter.log('Uploading %s ...' % self.oDebug.sImgPath);
1507 sFileVBoxServiceHst = self.oDebug.sImgPath;
1508 sFileVBoxServiceGst = "/tmp/VBoxService-txs";
1509 oTxsSession.syncUploadFile(sFileVBoxServiceHst, sFileVBoxServiceGst);
1510 oTxsSession.syncChMod(sFileVBoxServiceGst, 0o755);
1511 reporter.log('Executing VBoxService (in background)...');
1512 oTxsSession.syncExec(sFileVBoxServiceGst, (sFileVBoxServiceGst, "-vvvv", "--only-control", \
1513 "--logfile", "/tmp/VBoxService-txs.log") );
1514 elif oTestVm.isWindows():
1515 reporter.log('Uploading %s ...' % self.oDebug.sImgPath);
1516 sFileVBoxServiceHst = self.oDebug.sImgPath;
1517 sFileVBoxServiceGst = os.path.join(self.oTstDrv.getGuestSystemDir(oTestVm), 'VBoxService.exe');
1518 oTxsSession.syncUploadFile(sFileVBoxServiceHst, sFileVBoxServiceGst);
1519 sPathSC = os.path.join(self.oTstDrv.getGuestSystemDir(oTestVm), 'sc.exe');
1520 oTxsSession.syncExec(sPathSC, (sPathSC, "stop", "VBoxService") );
1521 time.sleep(5);
1522 oTxsSession.syncExec(sPathSC, (sPathSC, "start", "VBoxService") );
1523
1524 else: ## @todo Implement others.
1525 reporter.log('Debugging not available on this guest OS yet, skipping ...');
1526
1527 self.vboxServiceControl(oTxsSession, oTestVm, fStart = True);
1528
1529 except:
1530 return reporter.errorXcpt('Unable to prepare for debugging');
1531
1532 return True;
1533
1534 #
1535 # VBoxService handling.
1536 #
1537 def vboxServiceControl(self, oTxsSession, oTestVm, fStart):
1538 """
1539 Controls VBoxService on the guest by starting or stopping the service.
1540 Returns success indicator.
1541 """
1542
1543 fRc = True;
1544
1545 if oTestVm.isWindows():
1546 sPathSC = os.path.join(self.oTstDrv.getGuestSystemDir(oTestVm), 'sc.exe');
1547 if fStart is True:
1548 fRc = self.oTstDrv.txsRunTest(oTxsSession, 'Starting VBoxService with verbose logging', 30 * 1000, \
1549 sPathSC, (sPathSC, 'start', 'VBoxService'));
1550 else:
1551 fRc = self.oTstDrv.txsRunTest(oTxsSession, 'Stopping VBoxService', 30 * 1000, \
1552 sPathSC, (sPathSC, 'stop', 'VBoxService'));
1553 else:
1554 reporter.log('Controlling VBoxService not supported for this guest yet');
1555
1556 return fRc;
1557
1558 def waitForGuestFacility(self, oSession, eFacilityType, sDesc,
1559 eFacilityStatus, cMsTimeout = 30 * 1000):
1560 """
1561 Waits for a guest facility to enter a certain status.
1562 By default the "Active" status is being used.
1563
1564 Returns success status.
1565 """
1566
1567 reporter.log('Waiting for Guest Additions facility "%s" to change to status %s (%dms timeout)...'
1568 % (sDesc, str(eFacilityStatus), cMsTimeout));
1569
1570 fRc = False;
1571
1572 eStatusOld = None;
1573 tsStart = base.timestampMilli();
1574 while base.timestampMilli() - tsStart < cMsTimeout:
1575 try:
1576 eStatus, _ = oSession.o.console.guest.getFacilityStatus(eFacilityType);
1577 reporter.log('Current status is %s' % (str(eStatus)));
1578 if eStatusOld is None:
1579 eStatusOld = eStatus;
1580 except:
1581 reporter.errorXcpt('Getting facility status failed');
1582 break;
1583 if eStatus != eStatusOld:
1584 reporter.log('Status changed to %s' % (str(eStatus)));
1585 eStatusOld = eStatus;
1586 if eStatus == eFacilityStatus:
1587 fRc = True;
1588 break;
1589 self.oTstDrv.sleep(5); # Do some busy waiting.
1590
1591 if not fRc:
1592 reporter.error('Waiting for Guest Additions facility "%s" timed out' % (sDesc));
1593 else:
1594 reporter.log('Guest Additions facility "%s" reached requested status %s after %dms'
1595 % (sDesc, str(eFacilityStatus), base.timestampMilli() - tsStart));
1596
1597 return fRc;
1598
1599 #
1600 # Guest test files.
1601 #
1602
1603 def prepareGuestForTesting(self, oSession, oTxsSession, oTestVm):
1604 """
1605 Prepares the VM for testing, uploading a bunch of files and stuff via TXS.
1606 Returns success indicator.
1607 """
1608 _ = oSession;
1609
1610 #
1611 # Wait for VBoxService to come up.
1612 #
1613 reporter.testStart('Waiting for VBoxService to get started');
1614 fRc = self.waitForGuestFacility(oSession, vboxcon.AdditionsFacilityType_VBoxService, "VBoxService",
1615 vboxcon.AdditionsFacilityStatus_Active);
1616 reporter.testDone();
1617 if not fRc:
1618 return (False, oTxsSession);
1619
1620 #
1621 # Make sure the temporary directory exists.
1622 #
1623 for sDir in [self.oTstDrv.getGuestTempDir(oTestVm), ]:
1624 if oTxsSession.syncMkDirPath(sDir, 0o777) is not True:
1625 return reporter.error('Failed to create directory "%s"!' % (sDir,));
1626
1627 #
1628 # Enable VBoxService verbose logging.
1629 #
1630 self.oDebug.sVBoxServiceLogPath = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), "VBoxService");
1631 if oTxsSession.syncMkDirPath(self.oDebug.sVBoxServiceLogPath, 0o777) is not True:
1632 return reporter.error('Failed to create directory "%s"!' % (self.oDebug.sVBoxServiceLogPath,));
1633 sPathLogFile = oTestVm.pathJoin(self.oDebug.sVBoxServiceLogPath, 'VBoxService.log');
1634
1635 reporter.log('VBoxService logs will be stored in "%s"' % (self.oDebug.sVBoxServiceLogPath,));
1636
1637 if oTestVm.isWindows():
1638 sPathRegExe = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'reg.exe');
1639 sPathVBoxServiceExe = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'VBoxService.exe');
1640 sImagePath = '%s -vvvv --logfile %s' % (sPathVBoxServiceExe, sPathLogFile);
1641 self.oTstDrv.txsRunTest(oTxsSession, 'Enabling VBoxService verbose logging (via registry)', 30 * 1000,
1642 sPathRegExe,
1643 (sPathRegExe, 'add',
1644 '"HKLM\\SYSTEM\\CurrentControlSet\\Services\\VBoxService"',
1645 '/v', 'ImagePath', '/t', 'REG_SZ', '/d', sImagePath, '/f'));
1646
1647 self.vboxServiceControl(oTxsSession, oTestVm, fStart = False);
1648 time.sleep(5);
1649 self.vboxServiceControl(oTxsSession, oTestVm, fStart = True);
1650
1651 else:
1652 reporter.log('Verbose logging for VBoxService not supported for this guest yet');
1653
1654 #
1655 # Generate and upload some random files and dirs to the guest.
1656 # Note! Make sure we don't run into too-long-path issues when using
1657 # the test files on the host if.
1658 #
1659 cchGst = len(self.oTstDrv.getGuestTempDir(oTestVm)) + 1 + len('addgst-1') + 1;
1660 cchHst = len(self.oTstDrv.sScratchPath) + 1 + len('copyto/addgst-1') + 1;
1661 cchMaxPath = 230;
1662 if cchHst > cchGst:
1663 cchMaxPath -= cchHst - cchGst;
1664 reporter.log('cchMaxPath=%s (cchHst=%s, cchGst=%s)' % (cchMaxPath, cchHst, cchGst,));
1665 asCompatibleWith = None;
1666 if oTestVm.isWindows():
1667 asCompatibleWith = [ 'win' ];
1668 self.oTestFiles = vboxtestfileset.TestFileSet(oTestVm,
1669 self.oTstDrv.getGuestTempDir(oTestVm), 'addgst-1',
1670 cchMaxPath = cchMaxPath, asCompatibleWith = asCompatibleWith);
1671 return self.oTestFiles.upload(oTxsSession, self.oTstDrv);
1672
1673
1674 #
1675 # gctrlXxxx stuff.
1676 #
1677
1678 def gctrlCopyFileFrom(self, oGuestSession, oTest, fExpected):
1679 """
1680 Helper function to copy a single file from the guest to the host.
1681 """
1682 #
1683 # Do the copying.
1684 #
1685 reporter.log2('Copying guest file "%s" to host "%s"' % (limitString(oTest.sSrc), limitString(oTest.sDst)));
1686 try:
1687 if self.oTstDrv.fpApiVer >= 5.0:
1688 oCurProgress = oGuestSession.fileCopyFromGuest(oTest.sSrc, oTest.sDst, oTest.afFlags);
1689 else:
1690 oCurProgress = oGuestSession.copyFrom(oTest.sSrc, oTest.sDst, oTest.afFlags);
1691 except:
1692 reporter.maybeErrXcpt(fExpected, 'Copy from exception for sSrc="%s", sDst="%s":' % (oTest.sSrc, oTest.sDst,));
1693 return False;
1694 if oCurProgress is None:
1695 return reporter.error('No progress object returned');
1696 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlFileCopyFrom");
1697 oProgress.wait();
1698 if not oProgress.isSuccess():
1699 oProgress.logResult(fIgnoreErrors = not fExpected);
1700 return False;
1701
1702 #
1703 # Check the result if we can.
1704 #
1705 if oTest.oSrc:
1706 assert isinstance(oTest.oSrc, testfileset.TestFile);
1707 sDst = oTest.sDst;
1708 if os.path.isdir(sDst):
1709 sDst = os.path.join(sDst, oTest.oSrc.sName);
1710 try:
1711 oFile = open(sDst, 'rb');
1712 except:
1713 return reporter.errorXcpt('open(%s) failed during verfication' % (sDst,));
1714 fEqual = oTest.oSrc.equalFile(oFile);
1715 oFile.close();
1716 if not fEqual:
1717 return reporter.error('Content differs for "%s"' % (sDst,));
1718
1719 return True;
1720
1721 def __compareTestDir(self, oDir, sHostPath): # type: (testfileset.TestDir, str) -> bool
1722 """
1723 Recursively compare the content of oDir and sHostPath.
1724
1725 Returns True on success, False + error logging on failure.
1726
1727 Note! This ASSUMES that nothing else was copied to sHostPath!
1728 """
1729 #
1730 # First check out all the entries and files in the directory.
1731 #
1732 dLeftUpper = dict(oDir.dChildrenUpper);
1733 try:
1734 asEntries = os.listdir(sHostPath);
1735 except:
1736 return reporter.errorXcpt('os.listdir(%s) failed' % (sHostPath,));
1737
1738 fRc = True;
1739 for sEntry in asEntries:
1740 sEntryUpper = sEntry.upper();
1741 if sEntryUpper not in dLeftUpper:
1742 fRc = reporter.error('Unexpected entry "%s" in "%s"' % (sEntry, sHostPath,));
1743 else:
1744 oFsObj = dLeftUpper[sEntryUpper];
1745 del dLeftUpper[sEntryUpper];
1746
1747 if isinstance(oFsObj, testfileset.TestFile):
1748 sFilePath = os.path.join(sHostPath, oFsObj.sName);
1749 try:
1750 oFile = open(sFilePath, 'rb');
1751 except:
1752 fRc = reporter.errorXcpt('open(%s) failed during verfication' % (sFilePath,));
1753 else:
1754 fEqual = oFsObj.equalFile(oFile);
1755 oFile.close();
1756 if not fEqual:
1757 fRc = reporter.error('Content differs for "%s"' % (sFilePath,));
1758
1759 # List missing entries:
1760 for sKey in dLeftUpper:
1761 oEntry = dLeftUpper[sKey];
1762 fRc = reporter.error('%s: Missing %s "%s" (src path: %s)'
1763 % (sHostPath, oEntry.sName,
1764 'file' if isinstance(oEntry, testfileset.TestFile) else 'directory', oEntry.sPath));
1765
1766 #
1767 # Recurse into subdirectories.
1768 #
1769 for oFsObj in oDir.aoChildren:
1770 if isinstance(oFsObj, testfileset.TestDir):
1771 fRc = self.__compareTestDir(oFsObj, os.path.join(sHostPath, oFsObj.sName)) and fRc;
1772 return fRc;
1773
1774 def gctrlCopyDirFrom(self, oGuestSession, oTest, fExpected):
1775 """
1776 Helper function to copy a directory from the guest to the host.
1777 """
1778 #
1779 # Do the copying.
1780 #
1781 reporter.log2('Copying guest dir "%s" to host "%s"' % (limitString(oTest.sSrc), limitString(oTest.sDst)));
1782 try:
1783 oCurProgress = oGuestSession.directoryCopyFromGuest(oTest.sSrc, oTest.sDst, oTest.afFlags);
1784 except:
1785 reporter.maybeErrXcpt(fExpected, 'Copy dir from exception for sSrc="%s", sDst="%s":' % (oTest.sSrc, oTest.sDst,));
1786 return False;
1787 if oCurProgress is None:
1788 return reporter.error('No progress object returned');
1789
1790 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlDirCopyFrom");
1791 oProgress.wait();
1792 if not oProgress.isSuccess():
1793 oProgress.logResult(fIgnoreErrors = not fExpected);
1794 return False;
1795
1796 #
1797 # Check the result if we can.
1798 #
1799 if oTest.oSrc:
1800 assert isinstance(oTest.oSrc, testfileset.TestDir);
1801 sDst = oTest.sDst;
1802 if oTest.fIntoDst:
1803 return self.__compareTestDir(oTest.oSrc, os.path.join(sDst, oTest.oSrc.sName));
1804 oDummy = testfileset.TestDir(None, 'dummy');
1805 oDummy.aoChildren = [oTest.oSrc,]
1806 oDummy.dChildrenUpper = { oTest.oSrc.sName.upper(): oTest.oSrc, };
1807 return self.__compareTestDir(oDummy, sDst);
1808 return True;
1809
1810 def gctrlCopyFileTo(self, oGuestSession, sSrc, sDst, afFlags, fIsError):
1811 """
1812 Helper function to copy a single file from the host to the guest.
1813 """
1814 reporter.log2('Copying host file "%s" to guest "%s" (flags %s)' % (limitString(sSrc), limitString(sDst), afFlags));
1815 try:
1816 if self.oTstDrv.fpApiVer >= 5.0:
1817 oCurProgress = oGuestSession.fileCopyToGuest(sSrc, sDst, afFlags);
1818 else:
1819 oCurProgress = oGuestSession.copyTo(sSrc, sDst, afFlags);
1820 except:
1821 reporter.maybeErrXcpt(fIsError, 'sSrc=%s sDst=%s' % (sSrc, sDst,));
1822 return False;
1823
1824 if oCurProgress is None:
1825 return reporter.error('No progress object returned');
1826 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlCopyFileTo");
1827
1828 try:
1829 oProgress.wait();
1830 if not oProgress.isSuccess():
1831 oProgress.logResult(fIgnoreErrors = not fIsError);
1832 return False;
1833 except:
1834 reporter.maybeErrXcpt(fIsError, 'Wait exception for sSrc="%s", sDst="%s":' % (sSrc, sDst));
1835 return False;
1836 return True;
1837
1838 def gctrlCopyDirTo(self, oGuestSession, sSrc, sDst, afFlags, fIsError):
1839 """
1840 Helper function to copy a directory tree from the host to the guest.
1841 """
1842 reporter.log2('Copying host directory "%s" to guest "%s" (flags %s)' % (limitString(sSrc), limitString(sDst), afFlags));
1843 try:
1844 oCurProgress = oGuestSession.directoryCopyToGuest(sSrc, sDst, afFlags);
1845 except:
1846 reporter.maybeErrXcpt(fIsError, 'sSrc=%s sDst=%s' % (sSrc, sDst,));
1847 return False;
1848
1849 if oCurProgress is None:
1850 return reporter.error('No progress object returned');
1851 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlCopyFileTo");
1852
1853 try:
1854 oProgress.wait();
1855 if not oProgress.isSuccess():
1856 oProgress.logResult(fIgnoreErrors = not fIsError);
1857 return False;
1858 except:
1859 reporter.maybeErrXcpt(fIsError, 'Wait exception for sSrc="%s", sDst="%s":' % (sSrc, sDst));
1860 return False;
1861 return True;
1862
1863 def gctrlCreateDir(self, oTest, oRes, oGuestSession):
1864 """
1865 Helper function to create a guest directory specified in the current test.
1866 """
1867 reporter.log2('Creating directory "%s"' % (limitString(oTest.sDirectory),));
1868 try:
1869 oGuestSession.directoryCreate(oTest.sDirectory, oTest.fMode, oTest.afFlags);
1870 except:
1871 reporter.maybeErrXcpt(oRes.fRc, 'Failed to create "%s" fMode=%o afFlags=%s'
1872 % (oTest.sDirectory, oTest.fMode, oTest.afFlags,));
1873 return not oRes.fRc;
1874 if oRes.fRc is not True:
1875 return reporter.error('Did not expect to create directory "%s"!' % (oTest.sDirectory,));
1876
1877 # Check if the directory now exists.
1878 try:
1879 if self.oTstDrv.fpApiVer >= 5.0:
1880 fDirExists = oGuestSession.directoryExists(oTest.sDirectory, False);
1881 else:
1882 fDirExists = oGuestSession.directoryExists(oTest.sDirectory);
1883 except:
1884 return reporter.errorXcpt('directoryExists failed on "%s"!' % (oTest.sDirectory,));
1885 if not fDirExists:
1886 return reporter.errorXcpt('directoryExists returned False on "%s" after directoryCreate succeeded!'
1887 % (oTest.sDirectory,));
1888 return True;
1889
1890 def gctrlReadDirTree(self, oTest, oGuestSession, fIsError, sSubDir = None):
1891 """
1892 Helper function to recursively read a guest directory tree specified in the current test.
1893 """
1894 sDir = oTest.sDirectory;
1895 sFilter = oTest.sFilter;
1896 afFlags = oTest.afFlags;
1897 oTestVm = oTest.oCreds.oTestVm;
1898 sCurDir = oTestVm.pathJoin(sDir, sSubDir) if sSubDir else sDir;
1899
1900 fRc = True; # Be optimistic.
1901 cDirs = 0; # Number of directories read.
1902 cFiles = 0; # Number of files read.
1903 cOthers = 0; # Other files.
1904
1905 # Open the directory:
1906 reporter.log2('Directory="%s", filter="%s", afFlags="%s"' % (limitString(sCurDir), sFilter, afFlags));
1907 try:
1908 oCurDir = oGuestSession.directoryOpen(sCurDir, sFilter, afFlags);
1909 except:
1910 reporter.maybeErrXcpt(fIsError, 'sCurDir=%s sFilter=%s afFlags=%s' % (sCurDir, sFilter, afFlags,))
1911 return (False, 0, 0, 0);
1912
1913 # Read the directory.
1914 while fRc is True:
1915 try:
1916 oFsObjInfo = oCurDir.read();
1917 except Exception as oXcpt:
1918 if vbox.ComError.notEqual(oXcpt, vbox.ComError.VBOX_E_OBJECT_NOT_FOUND):
1919 if self.oTstDrv.fpApiVer > 5.2:
1920 reporter.errorXcpt('Error reading directory "%s":' % (sCurDir,));
1921 else:
1922 # Unlike fileOpen, directoryOpen will not fail if the directory does not exist.
1923 reporter.maybeErrXcpt(fIsError, 'Error reading directory "%s":' % (sCurDir,));
1924 fRc = False;
1925 else:
1926 reporter.log2('\tNo more directory entries for "%s"' % (limitString(sCurDir),));
1927 break;
1928
1929 try:
1930 sName = oFsObjInfo.name;
1931 eType = oFsObjInfo.type;
1932 except:
1933 fRc = reporter.errorXcpt();
1934 break;
1935
1936 if sName in ('.', '..', ):
1937 if eType != vboxcon.FsObjType_Directory:
1938 fRc = reporter.error('Wrong type for "%s": %d, expected %d (Directory)'
1939 % (sName, eType, vboxcon.FsObjType_Directory));
1940 elif eType == vboxcon.FsObjType_Directory:
1941 reporter.log2(' Directory "%s"' % limitString(oFsObjInfo.name));
1942 aSubResult = self.gctrlReadDirTree(oTest, oGuestSession, fIsError,
1943 oTestVm.pathJoin(sSubDir, sName) if sSubDir else sName);
1944 fRc = aSubResult[0];
1945 cDirs += aSubResult[1] + 1;
1946 cFiles += aSubResult[2];
1947 cOthers += aSubResult[3];
1948 elif eType is vboxcon.FsObjType_File:
1949 reporter.log4(' File "%s"' % oFsObjInfo.name);
1950 cFiles += 1;
1951 elif eType is vboxcon.FsObjType_Symlink:
1952 reporter.log4(' Symlink "%s" -- not tested yet' % oFsObjInfo.name);
1953 cOthers += 1;
1954 elif oTestVm.isWindows() \
1955 or oTestVm.isOS2() \
1956 or eType not in (vboxcon.FsObjType_Fifo, vboxcon.FsObjType_DevChar, vboxcon.FsObjType_DevBlock,
1957 vboxcon.FsObjType_Socket, vboxcon.FsObjType_WhiteOut):
1958 fRc = reporter.error('Directory "%s" contains invalid directory entry "%s" (type %d)' %
1959 (sCurDir, oFsObjInfo.name, oFsObjInfo.type,));
1960 else:
1961 cOthers += 1;
1962
1963 # Close the directory
1964 try:
1965 oCurDir.close();
1966 except:
1967 fRc = reporter.errorXcpt('sCurDir=%s' % (sCurDir));
1968
1969 return (fRc, cDirs, cFiles, cOthers);
1970
1971 def gctrlReadDirTree2(self, oGuestSession, oDir): # type: (testfileset.TestDir) -> bool
1972 """
1973 Helper function to recursively read a guest directory tree specified in the current test.
1974 """
1975
1976 #
1977 # Process the directory.
1978 #
1979
1980 # Open the directory:
1981 try:
1982 oCurDir = oGuestSession.directoryOpen(oDir.sPath, '', None);
1983 except:
1984 return reporter.errorXcpt('sPath=%s' % (oDir.sPath,));
1985
1986 # Read the directory.
1987 dLeftUpper = dict(oDir.dChildrenUpper);
1988 cDot = 0;
1989 cDotDot = 0;
1990 fRc = True;
1991 while True:
1992 try:
1993 oFsObjInfo = oCurDir.read();
1994 except Exception as oXcpt:
1995 if vbox.ComError.notEqual(oXcpt, vbox.ComError.VBOX_E_OBJECT_NOT_FOUND):
1996 fRc = reporter.errorXcpt('Error reading directory "%s":' % (oDir.sPath,));
1997 break;
1998
1999 try:
2000 sName = oFsObjInfo.name;
2001 eType = oFsObjInfo.type;
2002 cbFile = oFsObjInfo.objectSize;
2003 ## @todo check further attributes.
2004 except:
2005 fRc = reporter.errorXcpt();
2006 break;
2007
2008 # '.' and '..' entries are not present in oDir.aoChildren, so special treatment:
2009 if sName in ('.', '..', ):
2010 if eType != vboxcon.FsObjType_Directory:
2011 fRc = reporter.error('Wrong type for "%s": %d, expected %d (Directory)'
2012 % (sName, eType, vboxcon.FsObjType_Directory));
2013 if sName == '.': cDot += 1;
2014 else: cDotDot += 1;
2015 else:
2016 # Find the child and remove it from the dictionary.
2017 sNameUpper = sName.upper();
2018 oFsObj = dLeftUpper.get(sNameUpper);
2019 if oFsObj is None:
2020 fRc = reporter.error('Unknown object "%s" found in "%s" (type %s, size %s)!'
2021 % (sName, oDir.sPath, eType, cbFile,));
2022 else:
2023 del dLeftUpper[sNameUpper];
2024
2025 # Check type
2026 if isinstance(oFsObj, testfileset.TestDir):
2027 if eType != vboxcon.FsObjType_Directory:
2028 fRc = reporter.error('%s: expected directory (%d), got eType=%d!'
2029 % (oFsObj.sPath, vboxcon.FsObjType_Directory, eType,));
2030 elif isinstance(oFsObj, testfileset.TestFile):
2031 if eType != vboxcon.FsObjType_File:
2032 fRc = reporter.error('%s: expected file (%d), got eType=%d!'
2033 % (oFsObj.sPath, vboxcon.FsObjType_File, eType,));
2034 else:
2035 fRc = reporter.error('%s: WTF? type=%s' % (oFsObj.sPath, type(oFsObj),));
2036
2037 # Check the name.
2038 if oFsObj.sName != sName:
2039 fRc = reporter.error('%s: expected name "%s", got "%s" instead!' % (oFsObj.sPath, oFsObj.sName, sName,));
2040
2041 # Check the size if a file.
2042 if isinstance(oFsObj, testfileset.TestFile) and cbFile != oFsObj.cbContent:
2043 fRc = reporter.error('%s: expected size %s, got %s instead!' % (oFsObj.sPath, oFsObj.cbContent, cbFile,));
2044
2045 ## @todo check timestamps and attributes.
2046
2047 # Close the directory
2048 try:
2049 oCurDir.close();
2050 except:
2051 fRc = reporter.errorXcpt('oDir.sPath=%s' % (oDir.sPath,));
2052
2053 # Any files left over?
2054 for sKey in dLeftUpper:
2055 oFsObj = dLeftUpper[sKey];
2056 fRc = reporter.error('%s: Was not returned! (%s)' % (oFsObj.sPath, type(oFsObj),));
2057
2058 # Check the dot and dot-dot counts.
2059 if cDot != 1:
2060 fRc = reporter.error('%s: Found %s "." entries, expected exactly 1!' % (oDir.sPath, cDot,));
2061 if cDotDot != 1:
2062 fRc = reporter.error('%s: Found %s ".." entries, expected exactly 1!' % (oDir.sPath, cDotDot,));
2063
2064 #
2065 # Recurse into subdirectories using info from oDir.
2066 #
2067 for oFsObj in oDir.aoChildren:
2068 if isinstance(oFsObj, testfileset.TestDir):
2069 fRc = self.gctrlReadDirTree2(oGuestSession, oFsObj) and fRc;
2070
2071 return fRc;
2072
2073 def gctrlExecDoTest(self, i, oTest, oRes, oGuestSession):
2074 """
2075 Wrapper function around gctrlExecute to provide more sanity checking
2076 when needed in actual execution tests.
2077 """
2078 reporter.log('Testing #%d, cmd="%s" ...' % (i, oTest.sCmd));
2079 fRcExec = self.gctrlExecute(oTest, oGuestSession, oRes.fRc);
2080 if fRcExec == oRes.fRc:
2081 fRc = True;
2082 if fRcExec is True:
2083 # Compare exit status / code on successful process execution.
2084 if oTest.uExitStatus != oRes.uExitStatus \
2085 or oTest.iExitCode != oRes.iExitCode:
2086 fRc = reporter.error('Test #%d (%s) failed: Got exit status + code %d,%d, expected %d,%d'
2087 % (i, oTest.asArgs, oTest.uExitStatus, oTest.iExitCode,
2088 oRes.uExitStatus, oRes.iExitCode));
2089
2090 # Compare test / result buffers on successful process execution.
2091 if oTest.sBuf is not None and oRes.sBuf is not None:
2092 if not utils.areBytesEqual(oTest.sBuf, oRes.sBuf):
2093 fRc = reporter.error('Test #%d (%s) failed: Got buffer\n%s (%d bytes), expected\n%s (%d bytes)'
2094 % (i, oTest.asArgs,
2095 map(hex, map(ord, oTest.sBuf)), len(oTest.sBuf),
2096 map(hex, map(ord, oRes.sBuf)), len(oRes.sBuf)));
2097 reporter.log2('Test #%d passed: Buffers match (%d bytes)' % (i, len(oRes.sBuf)));
2098 elif oRes.sBuf and not oTest.sBuf:
2099 fRc = reporter.error('Test #%d (%s) failed: Got no buffer data, expected\n%s (%dbytes)' %
2100 (i, oTest.asArgs, map(hex, map(ord, oRes.sBuf)), len(oRes.sBuf),));
2101
2102 if oRes.cbStdOut is not None and oRes.cbStdOut != oTest.cbStdOut:
2103 fRc = reporter.error('Test #%d (%s) failed: Got %d bytes of stdout data, expected %d'
2104 % (i, oTest.asArgs, oTest.cbStdOut, oRes.cbStdOut));
2105 if oRes.cbStdErr is not None and oRes.cbStdErr != oTest.cbStdErr:
2106 fRc = reporter.error('Test #%d (%s) failed: Got %d bytes of stderr data, expected %d'
2107 % (i, oTest.asArgs, oTest.cbStdErr, oRes.cbStdErr));
2108 else:
2109 fRc = reporter.error('Test #%d (%s) failed: Got %s, expected %s' % (i, oTest.asArgs, fRcExec, oRes.fRc));
2110 return fRc;
2111
2112 def gctrlExecute(self, oTest, oGuestSession, fIsError): # pylint: disable=too-many-statements
2113 """
2114 Helper function to execute a program on a guest, specified in the current test.
2115
2116 Note! This weirdo returns results (process exitcode and status) in oTest.
2117 """
2118 fRc = True; # Be optimistic.
2119
2120 # Reset the weird result stuff:
2121 oTest.cbStdOut = 0;
2122 oTest.cbStdErr = 0;
2123 oTest.sBuf = '';
2124 oTest.uExitStatus = 0;
2125 oTest.iExitCode = 0;
2126
2127 ## @todo Compare execution timeouts!
2128 #tsStart = base.timestampMilli();
2129
2130 try:
2131 reporter.log2('Using session user=%s, sDomain=%s, name=%s, timeout=%d'
2132 % (oGuestSession.user, oGuestSession.domain, oGuestSession.name, oGuestSession.timeout,));
2133 except:
2134 return reporter.errorXcpt();
2135
2136 #
2137 # Start the process:
2138 #
2139 reporter.log2('Executing sCmd=%s, afFlags=%s, timeoutMS=%d, asArgs=%s, asEnv=%s'
2140 % (oTest.sCmd, oTest.afFlags, oTest.timeoutMS, limitString(oTest.asArgs), limitString(oTest.aEnv),));
2141 try:
2142 oProcess = oGuestSession.processCreate(oTest.sCmd,
2143 oTest.asArgs if self.oTstDrv.fpApiVer >= 5.0 else oTest.asArgs[1:],
2144 oTest.aEnv, oTest.afFlags, oTest.timeoutMS);
2145 except:
2146 reporter.maybeErrXcpt(fIsError, 'type=%s, asArgs=%s' % (type(oTest.asArgs), oTest.asArgs,));
2147 return False;
2148 if oProcess is None:
2149 return reporter.error('oProcess is None! (%s)' % (oTest.asArgs,));
2150
2151 #time.sleep(5); # try this if you want to see races here.
2152
2153 # Wait for the process to start properly:
2154 reporter.log2('Process start requested, waiting for start (%dms) ...' % (oTest.timeoutMS,));
2155 iPid = -1;
2156 aeWaitFor = [ vboxcon.ProcessWaitForFlag_Start, ];
2157 try:
2158 eWaitResult = oProcess.waitForArray(aeWaitFor, oTest.timeoutMS);
2159 except:
2160 reporter.maybeErrXcpt(fIsError, 'waitforArray failed for asArgs=%s' % (oTest.asArgs,));
2161 fRc = False;
2162 else:
2163 try:
2164 eStatus = oProcess.status;
2165 iPid = oProcess.PID;
2166 except:
2167 fRc = reporter.errorXcpt('asArgs=%s' % (oTest.asArgs,));
2168 else:
2169 reporter.log2('Wait result returned: %d, current process status is: %d' % (eWaitResult, eStatus,));
2170
2171 #
2172 # Wait for the process to run to completion if necessary.
2173 #
2174 # Note! The above eWaitResult return value can be ignored as it will
2175 # (mostly) reflect the process status anyway.
2176 #
2177 if eStatus == vboxcon.ProcessStatus_Started:
2178
2179 # What to wait for:
2180 aeWaitFor = [ vboxcon.ProcessWaitForFlag_Terminate, ];
2181 if vboxcon.ProcessCreateFlag_WaitForStdOut in oTest.afFlags:
2182 aeWaitFor.append(vboxcon.ProcessWaitForFlag_StdOut);
2183 if vboxcon.ProcessCreateFlag_WaitForStdErr in oTest.afFlags:
2184 aeWaitFor.append(vboxcon.ProcessWaitForFlag_StdErr);
2185 ## @todo Add vboxcon.ProcessWaitForFlag_StdIn.
2186
2187 reporter.log2('Process (PID %d) started, waiting for termination (%dms), aeWaitFor=%s ...'
2188 % (iPid, oTest.timeoutMS, aeWaitFor));
2189 acbFdOut = [0,0,0];
2190 while True:
2191 try:
2192 eWaitResult = oProcess.waitForArray(aeWaitFor, oTest.timeoutMS);
2193 except KeyboardInterrupt: # Not sure how helpful this is, but whatever.
2194 reporter.error('Process (PID %d) execution interrupted' % (iPid,));
2195 try: oProcess.close();
2196 except: pass;
2197 break;
2198 except:
2199 fRc = reporter.errorXcpt('asArgs=%s' % (oTest.asArgs,));
2200 break;
2201 #reporter.log2('Wait returned: %d' % (eWaitResult,));
2202
2203 # Process output:
2204 for eFdResult, iFd, sFdNm in [ (vboxcon.ProcessWaitResult_StdOut, 1, 'stdout'),
2205 (vboxcon.ProcessWaitResult_StdErr, 2, 'stderr'), ]:
2206 if eWaitResult in (eFdResult, vboxcon.ProcessWaitResult_WaitFlagNotSupported):
2207 try:
2208 abBuf = oProcess.read(iFd, 64 * 1024, oTest.timeoutMS);
2209 except KeyboardInterrupt: # Not sure how helpful this is, but whatever.
2210 reporter.error('Process (PID %d) execution interrupted' % (iPid,));
2211 try: oProcess.close();
2212 except: pass;
2213 except:
2214 reporter.maybeErrXcpt(fIsError, 'asArgs=%s' % (oTest.asArgs,));
2215 else:
2216 if abBuf:
2217 reporter.log2('Process (PID %d) got %d bytes of %s data (type: %s)'
2218 % (iPid, len(abBuf), sFdNm, type(abBuf)));
2219 if reporter.getVerbosity() >= 4:
2220 sBuf = '';
2221 if sys.version_info >= (2, 7):
2222 if isinstance(abBuf, memoryview): ## @todo Why is this happening?
2223 abBuf = abBuf.tobytes();
2224 sBuf = abBuf.decode("utf-8");
2225 if isinstance(abBuf, buffer):
2226 sBuf = str(abBuf);
2227 for sLine in sBuf.splitlines():
2228 reporter.log4('%s: %s' % (sFdNm, sLine));
2229 acbFdOut[iFd] += len(abBuf);
2230 oTest.sBuf = abBuf; ## @todo Figure out how to uniform + append!
2231
2232 ## Process input (todo):
2233 #if eWaitResult in (vboxcon.ProcessWaitResult_StdIn, vboxcon.ProcessWaitResult_WaitFlagNotSupported):
2234 # reporter.log2('Process (PID %d) needs stdin data' % (iPid,));
2235
2236 # Termination or error?
2237 if eWaitResult in (vboxcon.ProcessWaitResult_Terminate,
2238 vboxcon.ProcessWaitResult_Error,
2239 vboxcon.ProcessWaitResult_Timeout,):
2240 try: eStatus = oProcess.status;
2241 except: fRc = reporter.errorXcpt('asArgs=%s' % (oTest.asArgs,));
2242 reporter.log2('Process (PID %d) reported terminate/error/timeout: %d, status: %d'
2243 % (iPid, eWaitResult, eStatus,));
2244 break;
2245
2246 # End of the wait loop.
2247 _, oTest.cbStdOut, oTest.cbStdErr = acbFdOut;
2248
2249 try: eStatus = oProcess.status;
2250 except: fRc = reporter.errorXcpt('asArgs=%s' % (oTest.asArgs,));
2251 reporter.log2('Final process status (PID %d) is: %d' % (iPid, eStatus));
2252 reporter.log2('Process (PID %d) %d stdout, %d stderr' % (iPid, oTest.cbStdOut, oTest.cbStdErr));
2253
2254 #
2255 # Get the final status and exit code of the process.
2256 #
2257 try:
2258 oTest.uExitStatus = oProcess.status;
2259 oTest.iExitCode = oProcess.exitCode;
2260 except:
2261 fRc = reporter.errorXcpt('asArgs=%s' % (oTest.asArgs,));
2262 reporter.log2('Process (PID %d) has exit code: %d; status: %d ' % (iPid, oTest.iExitCode, oTest.uExitStatus));
2263 return fRc;
2264
2265 def testGuestCtrlSessionEnvironment(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
2266 """
2267 Tests the guest session environment changes.
2268 """
2269 aoTests = [
2270 # Check basic operations.
2271 tdTestSessionEx([ # Initial environment is empty.
2272 tdStepSessionCheckEnv(),
2273 # Check clearing empty env.
2274 tdStepSessionClearEnv(),
2275 tdStepSessionCheckEnv(),
2276 # Check set.
2277 tdStepSessionSetEnv('FOO', 'BAR'),
2278 tdStepSessionCheckEnv(['FOO=BAR',]),
2279 tdStepRequireMinimumApiVer(5.0), # 4.3 can't cope with the remainder.
2280 tdStepSessionClearEnv(),
2281 tdStepSessionCheckEnv(),
2282 # Check unset.
2283 tdStepSessionUnsetEnv('BAR'),
2284 tdStepSessionCheckEnv(['BAR']),
2285 tdStepSessionClearEnv(),
2286 tdStepSessionCheckEnv(),
2287 # Set + unset.
2288 tdStepSessionSetEnv('FOO', 'BAR'),
2289 tdStepSessionCheckEnv(['FOO=BAR',]),
2290 tdStepSessionUnsetEnv('FOO'),
2291 tdStepSessionCheckEnv(['FOO']),
2292 # Bulk environment changes (via attrib) (shall replace existing 'FOO').
2293 tdStepSessionBulkEnv( ['PATH=/bin:/usr/bin', 'TMPDIR=/var/tmp', 'USER=root']),
2294 tdStepSessionCheckEnv(['PATH=/bin:/usr/bin', 'TMPDIR=/var/tmp', 'USER=root']),
2295 ]),
2296 tdTestSessionEx([ # Check that setting the same value several times works.
2297 tdStepSessionSetEnv('FOO','BAR'),
2298 tdStepSessionCheckEnv([ 'FOO=BAR',]),
2299 tdStepSessionSetEnv('FOO','BAR2'),
2300 tdStepSessionCheckEnv([ 'FOO=BAR2',]),
2301 tdStepSessionSetEnv('FOO','BAR3'),
2302 tdStepSessionCheckEnv([ 'FOO=BAR3',]),
2303 tdStepRequireMinimumApiVer(5.0), # 4.3 can't cope with the remainder.
2304 # Add a little unsetting to the mix.
2305 tdStepSessionSetEnv('BAR', 'BEAR'),
2306 tdStepSessionCheckEnv([ 'FOO=BAR3', 'BAR=BEAR',]),
2307 tdStepSessionUnsetEnv('FOO'),
2308 tdStepSessionCheckEnv([ 'FOO', 'BAR=BEAR',]),
2309 tdStepSessionSetEnv('FOO','BAR4'),
2310 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR',]),
2311 # The environment is case sensitive.
2312 tdStepSessionSetEnv('foo','BAR5'),
2313 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR', 'foo=BAR5']),
2314 tdStepSessionUnsetEnv('foo'),
2315 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR', 'foo']),
2316 ]),
2317 tdTestSessionEx([ # Bulk settings merges stuff, last entry standing.
2318 tdStepSessionBulkEnv(['FOO=bar', 'foo=bar', 'FOO=doofus', 'TMPDIR=/tmp', 'foo=bar2']),
2319 tdStepSessionCheckEnv(['FOO=doofus', 'TMPDIR=/tmp', 'foo=bar2']),
2320 tdStepRequireMinimumApiVer(5.0), # 4.3 is buggy!
2321 tdStepSessionBulkEnv(['2=1+1', 'FOO=doofus2', ]),
2322 tdStepSessionCheckEnv(['2=1+1', 'FOO=doofus2' ]),
2323 ]),
2324 # Invalid variable names.
2325 tdTestSessionEx([
2326 tdStepSessionSetEnv('', 'FOO', vbox.ComError.E_INVALIDARG),
2327 tdStepSessionCheckEnv(),
2328 tdStepRequireMinimumApiVer(5.0), # 4.3 is too relaxed checking input!
2329 tdStepSessionBulkEnv(['', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2330 tdStepSessionCheckEnv(),
2331 tdStepSessionSetEnv('FOO=', 'BAR', vbox.ComError.E_INVALIDARG),
2332 tdStepSessionCheckEnv(),
2333 ]),
2334 # A bit more weird keys/values.
2335 tdTestSessionEx([ tdStepSessionSetEnv('$$$', ''),
2336 tdStepSessionCheckEnv([ '$$$=',]), ]),
2337 tdTestSessionEx([ tdStepSessionSetEnv('$$$', '%%%'),
2338 tdStepSessionCheckEnv([ '$$$=%%%',]),
2339 ]),
2340 tdTestSessionEx([ tdStepRequireMinimumApiVer(5.0), # 4.3 is buggy!
2341 tdStepSessionSetEnv(u'ß$%ß&', ''),
2342 tdStepSessionCheckEnv([ u'ß$%ß&=',]),
2343 ]),
2344 # Misc stuff.
2345 tdTestSessionEx([ tdStepSessionSetEnv('FOO', ''),
2346 tdStepSessionCheckEnv(['FOO=',]),
2347 ]),
2348 tdTestSessionEx([ tdStepSessionSetEnv('FOO', 'BAR'),
2349 tdStepSessionCheckEnv(['FOO=BAR',])
2350 ],),
2351 tdTestSessionEx([ tdStepSessionSetEnv('FOO', 'BAR'),
2352 tdStepSessionSetEnv('BAR', 'BAZ'),
2353 tdStepSessionCheckEnv([ 'FOO=BAR', 'BAR=BAZ',]),
2354 ]),
2355 ];
2356 # Leading '=' in the name is okay for windows guests in 6.1 and later (for driver letter CWDs).
2357 if (self.oTstDrv.fpApiVer < 6.1 and self.oTstDrv.fpApiVer >= 5.0) or not oTestVm.isWindows():
2358 aoTests.append(tdTestSessionEx([tdStepSessionSetEnv('=', '===', vbox.ComError.E_INVALIDARG),
2359 tdStepSessionCheckEnv(),
2360 tdStepSessionSetEnv('=FOO', 'BAR', vbox.ComError.E_INVALIDARG),
2361 tdStepSessionCheckEnv(),
2362 tdStepSessionBulkEnv(['=', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2363 tdStepSessionCheckEnv(),
2364 tdStepSessionBulkEnv(['=FOO', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2365 tdStepSessionCheckEnv(),
2366 tdStepSessionBulkEnv(['=D:=D:/tmp', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2367 tdStepSessionCheckEnv(),
2368 tdStepSessionSetEnv('=D:', 'D:/temp', vbox.ComError.E_INVALIDARG),
2369 tdStepSessionCheckEnv(),
2370 ]));
2371 elif self.oTstDrv.fpApiVer >= 6.1 and oTestVm.isWindows():
2372 aoTests.append(tdTestSessionEx([tdStepSessionSetEnv('=D:', 'D:/tmp'),
2373 tdStepSessionCheckEnv(['=D:=D:/tmp',]),
2374 tdStepSessionBulkEnv(['=D:=D:/temp', '=FOO', 'foo=bar']),
2375 tdStepSessionCheckEnv(['=D:=D:/temp', '=FOO', 'foo=bar']),
2376 tdStepSessionUnsetEnv('=D:'),
2377 tdStepSessionCheckEnv(['=D:', '=FOO', 'foo=bar']),
2378 ]));
2379
2380 return tdTestSessionEx.executeListTestSessions(aoTests, self.oTstDrv, oSession, oTxsSession, oTestVm, 'SessionEnv');
2381
2382 def testGuestCtrlSession(self, oSession, oTxsSession, oTestVm):
2383 """
2384 Tests the guest session handling.
2385 """
2386
2387 #
2388 # Tests:
2389 #
2390 atTests = [
2391 # Invalid parameters.
2392 [ tdTestSession(sUser = ''), tdTestResultSession() ],
2393 # User account without a passwort - forbidden.
2394 [ tdTestSession(sPassword = "" ), tdTestResultSession() ],
2395 # Various wrong credentials.
2396 # Note! Only windows cares about sDomain, the other guests ignores it.
2397 # Note! On Guest Additions < 4.3 this always succeeds because these don't
2398 # support creating dedicated sessions. Instead, guest process creation
2399 # then will fail. See note below.
2400 [ tdTestSession(sPassword = 'bar'), tdTestResultSession() ],
2401 [ tdTestSession(sUser = 'foo', sPassword = 'bar'), tdTestResultSession() ],
2402 [ tdTestSession(sPassword = 'bar', sDomain = 'boo'), tdTestResultSession() ],
2403 [ tdTestSession(sUser = 'foo', sPassword = 'bar', sDomain = 'boo'), tdTestResultSession() ],
2404 ];
2405 if oTestVm.isWindows(): # domain is ignored elsewhere.
2406 atTests.append([ tdTestSession(sDomain = 'boo'), tdTestResultSession() ]);
2407
2408 # Finally, correct credentials.
2409 atTests.append([ tdTestSession(), tdTestResultSession(fRc = True, cNumSessions = 1) ]);
2410
2411 #
2412 # Run the tests.
2413 #
2414 fRc = True;
2415 for (i, tTest) in enumerate(atTests):
2416 oCurTest = tTest[0] # type: tdTestSession
2417 oCurRes = tTest[1] # type: tdTestResult
2418
2419 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
2420 reporter.log('Testing #%d, user="%s", sPassword="%s", sDomain="%s" ...'
2421 % (i, oCurTest.oCreds.sUser, oCurTest.oCreds.sPassword, oCurTest.oCreds.sDomain));
2422 sCurGuestSessionName = 'testGuestCtrlSession: Test #%d' % (i,);
2423 fRc2, oCurGuestSession = oCurTest.createSession(sCurGuestSessionName, fIsError = oCurRes.fRc);
2424
2425 # See note about < 4.3 Guest Additions above.
2426 uProtocolVersion = 2;
2427 if oCurGuestSession is not None:
2428 try:
2429 uProtocolVersion = oCurGuestSession.protocolVersion;
2430 except:
2431 fRc = reporter.errorXcpt('Test #%d' % (i,));
2432
2433 if uProtocolVersion >= 2 and fRc2 is not oCurRes.fRc:
2434 fRc = reporter.error('Test #%d failed: Session creation failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc,));
2435
2436 if fRc2 and oCurGuestSession is None:
2437 fRc = reporter.error('Test #%d failed: no session object' % (i,));
2438 fRc2 = False;
2439
2440 if fRc2:
2441 if uProtocolVersion >= 2: # For Guest Additions < 4.3 getSessionCount() always will return 1.
2442 cCurSessions = oCurTest.getSessionCount(self.oTstDrv.oVBoxMgr);
2443 if cCurSessions != oCurRes.cNumSessions:
2444 fRc = reporter.error('Test #%d failed: Session count does not match: Got %d, expected %d'
2445 % (i, cCurSessions, oCurRes.cNumSessions));
2446 try:
2447 sObjName = oCurGuestSession.name;
2448 except:
2449 fRc = reporter.errorXcpt('Test #%d' % (i,));
2450 else:
2451 if sObjName != sCurGuestSessionName:
2452 fRc = reporter.error('Test #%d failed: Session name does not match: Got "%s", expected "%s"'
2453 % (i, sObjName, sCurGuestSessionName));
2454 fRc2 = oCurTest.closeSession();
2455 if fRc2 is False:
2456 fRc = reporter.error('Test #%d failed: Session could not be closed' % (i,));
2457
2458 if fRc is False:
2459 return (False, oTxsSession);
2460
2461 #
2462 # Multiple sessions.
2463 #
2464 cMaxGuestSessions = 31; # Maximum number of concurrent guest session allowed.
2465 # Actually, this is 32, but we don't test session 0.
2466 aoMultiSessions = {};
2467 reporter.log2('Opening multiple guest tsessions at once ...');
2468 for i in xrange(cMaxGuestSessions + 1):
2469 aoMultiSessions[i] = tdTestSession(sSessionName = 'MultiSession #%d' % (i,));
2470 aoMultiSessions[i].setEnvironment(oSession, oTxsSession, oTestVm);
2471
2472 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr);
2473 reporter.log2('MultiSession test #%d count is %d' % (i, cCurSessions));
2474 if cCurSessions != i:
2475 return (reporter.error('MultiSession count is %d, expected %d' % (cCurSessions, i)), oTxsSession);
2476 fRc2, _ = aoMultiSessions[i].createSession('MultiSession #%d' % (i,), i < cMaxGuestSessions);
2477 if fRc2 is not True:
2478 if i < cMaxGuestSessions:
2479 return (reporter.error('MultiSession #%d test failed' % (i,)), oTxsSession);
2480 reporter.log('MultiSession #%d exceeded concurrent guest session count, good' % (i,));
2481 break;
2482
2483 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr);
2484 if cCurSessions is not cMaxGuestSessions:
2485 return (reporter.error('Final session count %d, expected %d ' % (cCurSessions, cMaxGuestSessions,)), oTxsSession);
2486
2487 reporter.log2('Closing MultiSessions ...');
2488 for i in xrange(cMaxGuestSessions):
2489 # Close this session:
2490 oClosedGuestSession = aoMultiSessions[i].oGuestSession;
2491 fRc2 = aoMultiSessions[i].closeSession();
2492 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr)
2493 reporter.log2('MultiSession #%d count is %d' % (i, cCurSessions,));
2494 if fRc2 is False:
2495 fRc = reporter.error('Closing MultiSession #%d failed' % (i,));
2496 elif cCurSessions != cMaxGuestSessions - (i + 1):
2497 fRc = reporter.error('Expected %d session after closing #%d, got %d instead'
2498 % (cMaxGuestSessions - (i + 1), cCurSessions, i,));
2499 assert aoMultiSessions[i].oGuestSession is None or not fRc2;
2500 ## @todo any way to check that the session is closed other than the 'sessions' attribute?
2501
2502 # Try check that none of the remaining sessions got closed.
2503 try:
2504 aoGuestSessions = self.oTstDrv.oVBoxMgr.getArray(atTests[0][0].oGuest, 'sessions');
2505 except:
2506 return (reporter.errorXcpt('i=%d/%d' % (i, cMaxGuestSessions,)), oTxsSession);
2507 if oClosedGuestSession in aoGuestSessions:
2508 fRc = reporter.error('i=%d/%d: %s should not be in %s'
2509 % (i, cMaxGuestSessions, oClosedGuestSession, aoGuestSessions));
2510 if i + 1 < cMaxGuestSessions: # Not sure what xrange(2,2) does...
2511 for j in xrange(i + 1, cMaxGuestSessions):
2512 if aoMultiSessions[j].oGuestSession not in aoGuestSessions:
2513 fRc = reporter.error('i=%d/j=%d/%d: %s should be in %s'
2514 % (i, j, cMaxGuestSessions, aoMultiSessions[j].oGuestSession, aoGuestSessions));
2515 ## @todo any way to check that they work?
2516
2517 ## @todo Test session timeouts.
2518
2519 return (fRc, oTxsSession);
2520
2521 def testGuestCtrlSessionFileRefs(self, oSession, oTxsSession, oTestVm):
2522 """
2523 Tests the guest session file reference handling.
2524 """
2525
2526 # Find a file to play around with:
2527 sFile = self.oTstDrv.getGuestSystemFileForReading(oTestVm);
2528
2529 # Use credential defaults.
2530 oCreds = tdCtxCreds();
2531 oCreds.applyDefaultsIfNotSet(oTestVm);
2532
2533 # Number of stale guest files to create.
2534 cStaleFiles = 10;
2535
2536 #
2537 # Start a session.
2538 #
2539 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
2540 try:
2541 oGuest = oSession.o.console.guest;
2542 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionFileRefs");
2543 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
2544 except:
2545 return (reporter.errorXcpt(), oTxsSession);
2546
2547 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
2548 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
2549 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
2550 reporter.log('Session successfully started');
2551
2552 #
2553 # Open guest files and "forget" them (stale entries).
2554 # For them we don't have any references anymore intentionally.
2555 #
2556 reporter.log2('Opening stale files');
2557 fRc = True;
2558 for i in xrange(0, cStaleFiles):
2559 try:
2560 if self.oTstDrv.fpApiVer >= 5.0:
2561 oGuestSession.fileOpen(sFile, vboxcon.FileAccessMode_ReadOnly, vboxcon.FileOpenAction_OpenExisting, 0);
2562 else:
2563 oGuestSession.fileOpen(sFile, "r", "oe", 0);
2564 # Note: Use a timeout in the call above for not letting the stale processes
2565 # hanging around forever. This can happen if the installed Guest Additions
2566 # do not support terminating guest processes.
2567 except:
2568 fRc = reporter.errorXcpt('Opening stale file #%d failed:' % (i,));
2569 break;
2570
2571 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
2572 except: fRc = reporter.errorXcpt();
2573 else:
2574 if cFiles != cStaleFiles:
2575 fRc = reporter.error('Got %d stale files, expected %d' % (cFiles, cStaleFiles));
2576
2577 if fRc is True:
2578 #
2579 # Open non-stale files and close them again.
2580 #
2581 reporter.log2('Opening non-stale files');
2582 aoFiles = [];
2583 for i in xrange(0, cStaleFiles):
2584 try:
2585 if self.oTstDrv.fpApiVer >= 5.0:
2586 oCurFile = oGuestSession.fileOpen(sFile, vboxcon.FileAccessMode_ReadOnly,
2587 vboxcon.FileOpenAction_OpenExisting, 0);
2588 else:
2589 oCurFile = oGuestSession.fileOpen(sFile, "r", "oe", 0);
2590 aoFiles.append(oCurFile);
2591 except:
2592 fRc = reporter.errorXcpt('Opening non-stale file #%d failed:' % (i,));
2593 break;
2594
2595 # Check the count.
2596 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
2597 except: fRc = reporter.errorXcpt();
2598 else:
2599 if cFiles != cStaleFiles * 2:
2600 fRc = reporter.error('Got %d total files, expected %d' % (cFiles, cStaleFiles * 2));
2601
2602 # Close them.
2603 reporter.log2('Closing all non-stale files again ...');
2604 for i, oFile in enumerate(aoFiles):
2605 try:
2606 oFile.close();
2607 except:
2608 fRc = reporter.errorXcpt('Closing non-stale file #%d failed:' % (i,));
2609
2610 # Check the count again.
2611 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
2612 except: fRc = reporter.errorXcpt();
2613 # Here we count the stale files (that is, files we don't have a reference
2614 # anymore for) and the opened and then closed non-stale files (that we still keep
2615 # a reference in aoFiles[] for).
2616 if cFiles != cStaleFiles:
2617 fRc = reporter.error('Got %d total files, expected %d' % (cFiles, cStaleFiles));
2618
2619 #
2620 # Check that all (referenced) non-stale files are now in the "closed" state.
2621 #
2622 reporter.log2('Checking statuses of all non-stale files ...');
2623 for i, oFile in enumerate(aoFiles):
2624 try:
2625 eFileStatus = aoFiles[i].status;
2626 except:
2627 fRc = reporter.errorXcpt('Checking status of file #%d failed:' % (i,));
2628 else:
2629 if eFileStatus != vboxcon.FileStatus_Closed:
2630 fRc = reporter.error('Non-stale file #%d has status %d, expected %d'
2631 % (i, eFileStatus, vboxcon.FileStatus_Closed));
2632
2633 if fRc is True:
2634 reporter.log2('All non-stale files closed');
2635
2636 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
2637 except: fRc = reporter.errorXcpt();
2638 else: reporter.log2('Final guest session file count: %d' % (cFiles,));
2639
2640 #
2641 # Now try to close the session and see what happens.
2642 # Note! Session closing is why we've been doing all the 'if fRc is True' stuff above rather than returning.
2643 #
2644 reporter.log2('Closing guest session ...');
2645 try:
2646 oGuestSession.close();
2647 except:
2648 fRc = reporter.errorXcpt('Testing for stale processes failed:');
2649
2650 return (fRc, oTxsSession);
2651
2652 #def testGuestCtrlSessionDirRefs(self, oSession, oTxsSession, oTestVm):
2653 # """
2654 # Tests the guest session directory reference handling.
2655 # """
2656
2657 # fRc = True;
2658 # return (fRc, oTxsSession);
2659
2660 def testGuestCtrlSessionProcRefs(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
2661 """
2662 Tests the guest session process reference handling.
2663 """
2664
2665 sCmd = self.oTstDrv.getGuestSystemShell(oTestVm);
2666 asArgs = [sCmd,];
2667
2668 # Use credential defaults.
2669 oCreds = tdCtxCreds();
2670 oCreds.applyDefaultsIfNotSet(oTestVm);
2671
2672 # Number of stale guest processes to create.
2673 cStaleProcs = 10;
2674
2675 #
2676 # Start a session.
2677 #
2678 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
2679 try:
2680 oGuest = oSession.o.console.guest;
2681 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionProcRefs");
2682 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
2683 except:
2684 return (reporter.errorXcpt(), oTxsSession);
2685
2686 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
2687 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
2688 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
2689 reporter.log('Session successfully started');
2690
2691 #
2692 # Fire off forever-running processes and "forget" them (stale entries).
2693 # For them we don't have any references anymore intentionally.
2694 #
2695 reporter.log2('Starting stale processes...');
2696 fRc = True;
2697 for i in xrange(0, cStaleProcs):
2698 try:
2699 oGuestSession.processCreate(sCmd,
2700 asArgs if self.oTstDrv.fpApiVer >= 5.0 else asArgs[1:], [],
2701 [ vboxcon.ProcessCreateFlag_WaitForStdOut ], 30 * 1000);
2702 # Note: Use a timeout in the call above for not letting the stale processes
2703 # hanging around forever. This can happen if the installed Guest Additions
2704 # do not support terminating guest processes.
2705 except:
2706 fRc = reporter.errorXcpt('Creating stale process #%d failed:' % (i,));
2707 break;
2708
2709 try: cProcesses = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
2710 except: fRc = reporter.errorXcpt();
2711 else:
2712 if cProcesses != cStaleProcs:
2713 fRc = reporter.error('Got %d stale processes, expected %d' % (cProcesses, cStaleProcs));
2714
2715 if fRc is True:
2716 #
2717 # Fire off non-stale processes and wait for termination.
2718 #
2719 if oTestVm.isWindows() or oTestVm.isOS2():
2720 asArgs = [ sCmd, '/C', 'dir', '/S', self.oTstDrv.getGuestSystemDir(oTestVm), ];
2721 else:
2722 asArgs = [ sCmd, '-c', 'ls -la ' + self.oTstDrv.getGuestSystemDir(oTestVm), ];
2723 reporter.log2('Starting non-stale processes...');
2724 aoProcesses = [];
2725 for i in xrange(0, cStaleProcs):
2726 try:
2727 oCurProc = oGuestSession.processCreate(sCmd, asArgs if self.oTstDrv.fpApiVer >= 5.0 else asArgs[1:],
2728 [], [], 0); # Infinite timeout.
2729 aoProcesses.append(oCurProc);
2730 except:
2731 fRc = reporter.errorXcpt('Creating non-stale process #%d failed:' % (i,));
2732 break;
2733
2734 reporter.log2('Waiting for non-stale processes to terminate...');
2735 for i, oProcess in enumerate(aoProcesses):
2736 try:
2737 eWaitResult = oProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], 120 * 1000);
2738 eProcessStatus = oProcess.status;
2739 except:
2740 fRc = reporter.errorXcpt('Waiting for non-stale process #%d failed:' % (i,));
2741 else:
2742 if eProcessStatus != vboxcon.ProcessStatus_TerminatedNormally:
2743 fRc = reporter.error('Waiting for non-stale processes #%d resulted in status %d, expected %d (wr=%d)'
2744 % (i, eProcessStatus, vboxcon.ProcessStatus_TerminatedNormally, eWaitResult));
2745
2746 try: cProcesses = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
2747 except: fRc = reporter.errorXcpt();
2748 else:
2749 # Here we count the stale processes (that is, processes we don't have a reference
2750 # anymore for) and the started + terminated non-stale processes (that we still keep
2751 # a reference in aoProcesses[] for).
2752 if cProcesses != (cStaleProcs * 2):
2753 fRc = reporter.error('Got %d total processes, expected %d' % (cProcesses, cStaleProcs));
2754
2755 if fRc is True:
2756 reporter.log2('All non-stale processes terminated');
2757
2758 #
2759 # Fire off non-stale blocking processes which are terminated via terminate().
2760 #
2761 if oTestVm.isWindows() or oTestVm.isOS2():
2762 asArgs = [ sCmd, '/C', 'pause'];
2763 else:
2764 asArgs = [ sCmd ];
2765 reporter.log2('Starting blocking processes...');
2766 aoProcesses = [];
2767 for i in xrange(0, cStaleProcs):
2768 try:
2769 oCurProc = oGuestSession.processCreate(sCmd, asArgs if self.oTstDrv.fpApiVer >= 5.0 else asArgs[1:],
2770 [], [], 30 * 1000);
2771 # Note: Use a timeout in the call above for not letting the stale processes
2772 # hanging around forever. This can happen if the installed Guest Additions
2773 # do not support terminating guest processes.
2774 aoProcesses.append(oCurProc);
2775 except:
2776 fRc = reporter.errorXcpt('Creating non-stale blocking process #%d failed:' % (i,));
2777 break;
2778
2779 reporter.log2('Terminating blocking processes...');
2780 for i, oProcess in enumerate(aoProcesses):
2781 try:
2782 oProcess.terminate();
2783 except: # Termination might not be supported, just skip and log it.
2784 reporter.logXcpt('Termination of blocking process #%d failed, skipped:' % (i,));
2785
2786 # There still should be 20 processes because we terminated the 10 newest ones.
2787 try: cProcesses = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
2788 except: fRc = reporter.errorXcpt();
2789 else:
2790 if cProcesses != (cStaleProcs * 2):
2791 fRc = reporter.error('Got %d total processes, expected %d' % (cProcesses, cStaleProcs));
2792 reporter.log2('Final guest session processes count: %d' % (cProcesses,));
2793
2794 #
2795 # Now try to close the session and see what happens.
2796 #
2797 reporter.log2('Closing guest session ...');
2798 try:
2799 oGuestSession.close();
2800 except:
2801 fRc = reporter.errorXcpt('Testing for stale processes failed:');
2802
2803 return (fRc, oTxsSession);
2804
2805 def testGuestCtrlExec(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals,too-many-statements
2806 """
2807 Tests the basic execution feature.
2808 """
2809
2810 # Paths:
2811 sVBoxControl = None; ## @todo Get path of installed Guest Additions. Later.
2812 sShell = self.oTstDrv.getGuestSystemShell(oTestVm);
2813 sShellOpt = '/C' if oTestVm.isWindows() or oTestVm.isOS2() else '-c';
2814 sSystemDir = self.oTstDrv.getGuestSystemDir(oTestVm);
2815 sFileForReading = self.oTstDrv.getGuestSystemFileForReading(oTestVm);
2816 if oTestVm.isWindows() or oTestVm.isOS2():
2817 sImageOut = self.oTstDrv.getGuestSystemShell(oTestVm);
2818 if oTestVm.isWindows():
2819 sVBoxControl = "C:\\Program Files\\Oracle\\VirtualBox Guest Additions\\VBoxControl.exe";
2820 else:
2821 sImageOut = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'ls');
2822 if oTestVm.isLinux(): ## @todo check solaris and darwin.
2823 sVBoxControl = "/usr/bin/VBoxControl"; # Symlink
2824
2825 # Use credential defaults.
2826 oCreds = tdCtxCreds();
2827 oCreds.applyDefaultsIfNotSet(oTestVm);
2828
2829 atInvalid = [
2830 # Invalid parameters.
2831 [ tdTestExec(), tdTestResultExec() ],
2832 # Non-existent / invalid image.
2833 [ tdTestExec(sCmd = "non-existent"), tdTestResultExec() ],
2834 [ tdTestExec(sCmd = "non-existent2"), tdTestResultExec() ],
2835 # Use an invalid format string.
2836 [ tdTestExec(sCmd = "%$%%%&"), tdTestResultExec() ],
2837 # More stuff.
2838 [ tdTestExec(sCmd = u"ƒ‰‹ˆ÷‹¸"), tdTestResultExec() ],
2839 [ tdTestExec(sCmd = "???://!!!"), tdTestResultExec() ],
2840 [ tdTestExec(sCmd = "<>!\\"), tdTestResultExec() ],
2841 # Enable as soon as ERROR_BAD_DEVICE is implemented.
2842 #[ tdTestExec(sCmd = "CON", tdTestResultExec() ],
2843 ];
2844
2845 atExec = [];
2846 if oTestVm.isWindows() or oTestVm.isOS2():
2847 atExec += [
2848 # Basic execution.
2849 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
2850 tdTestResultExec(fRc = True) ],
2851 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sFileForReading ]),
2852 tdTestResultExec(fRc = True) ],
2853 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir + '\\nonexist.dll' ]),
2854 tdTestResultExec(fRc = True, iExitCode = 1) ],
2855 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', '/wrongparam' ]),
2856 tdTestResultExec(fRc = True, iExitCode = 1) ],
2857 [ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'wrongcommand' ]),
2858 tdTestResultExec(fRc = True, iExitCode = 1) ],
2859 # StdOut.
2860 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
2861 tdTestResultExec(fRc = True) ],
2862 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stdout-non-existing' ]),
2863 tdTestResultExec(fRc = True, iExitCode = 1) ],
2864 # StdErr.
2865 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
2866 tdTestResultExec(fRc = True) ],
2867 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stderr-non-existing' ]),
2868 tdTestResultExec(fRc = True, iExitCode = 1) ],
2869 # StdOut + StdErr.
2870 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
2871 tdTestResultExec(fRc = True) ],
2872 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stdouterr-non-existing' ]),
2873 tdTestResultExec(fRc = True, iExitCode = 1) ],
2874 ];
2875 # atExec.extend([
2876 # FIXME: Failing tests.
2877 # Environment variables.
2878 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_NONEXIST' ],
2879 # tdTestResultExec(fRc = True, iExitCode = 1) ]
2880 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'windir' ],
2881 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2882 # tdTestResultExec(fRc = True, sBuf = 'windir=C:\\WINDOWS\r\n') ],
2883 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
2884 # aEnv = [ 'TEST_FOO=BAR' ],
2885 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2886 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ],
2887 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
2888 # aEnv = [ 'TEST_FOO=BAR', 'TEST_BAZ=BAR' ],
2889 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2890 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ]
2891
2892 ## @todo Create some files (or get files) we know the output size of to validate output length!
2893 ## @todo Add task which gets killed at some random time while letting the guest output something.
2894 #];
2895 else:
2896 atExec += [
2897 # Basic execution.
2898 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '-R', sSystemDir ]),
2899 tdTestResultExec(fRc = True) ],
2900 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sFileForReading ]),
2901 tdTestResultExec(fRc = True) ],
2902 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '--wrong-parameter' ]),
2903 tdTestResultExec(fRc = True, iExitCode = 2) ],
2904 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/non/existent' ]),
2905 tdTestResultExec(fRc = True, iExitCode = 2) ],
2906 [ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'wrongcommand' ]),
2907 tdTestResultExec(fRc = True, iExitCode = 127) ],
2908 # StdOut.
2909 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
2910 tdTestResultExec(fRc = True) ],
2911 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stdout-non-existing' ]),
2912 tdTestResultExec(fRc = True, iExitCode = 2) ],
2913 # StdErr.
2914 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
2915 tdTestResultExec(fRc = True) ],
2916 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stderr-non-existing' ]),
2917 tdTestResultExec(fRc = True, iExitCode = 2) ],
2918 # StdOut + StdErr.
2919 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
2920 tdTestResultExec(fRc = True) ],
2921 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stdouterr-non-existing' ]),
2922 tdTestResultExec(fRc = True, iExitCode = 2) ],
2923 ];
2924 # atExec.extend([
2925 # FIXME: Failing tests.
2926 # Environment variables.
2927 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_NONEXIST' ],
2928 # tdTestResultExec(fRc = True, iExitCode = 1) ]
2929 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'windir' ],
2930 #
2931 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2932 # tdTestResultExec(fRc = True, sBuf = 'windir=C:\\WINDOWS\r\n') ],
2933 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
2934 # aEnv = [ 'TEST_FOO=BAR' ],
2935 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2936 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ],
2937 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
2938 # aEnv = [ 'TEST_FOO=BAR', 'TEST_BAZ=BAR' ],
2939 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2940 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ]
2941
2942 ## @todo Create some files (or get files) we know the output size of to validate output length!
2943 ## @todo Add task which gets killed at some random time while letting the guest output something.
2944 #];
2945
2946 #
2947 for iExitCode in xrange(0, 127):
2948 atExec.append([ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'exit %s' % iExitCode ]),
2949 tdTestResultExec(fRc = True, iExitCode = iExitCode) ]);
2950
2951 if sVBoxControl \
2952 and self.oTstDrv.fpApiVer >= 6.0: # Investigate with this doesn't work on (<) 5.2.
2953 # Paths with spaces on windows.
2954 atExec.append([ tdTestExec(sCmd = sVBoxControl, asArgs = [ sVBoxControl, 'version' ],
2955 afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut,
2956 vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2957 tdTestResultExec(fRc = True) ]);
2958
2959 # Test very long arguments.
2960 # Old(er) Windows OSes tend to crash in cmd.exe, so skip this.
2961 # Regarding paths:
2962 # - We have RTPATH_BIG_MAX (64K)
2963 # - MSDN says 32K for CreateFileW()
2964 # - On Windows, each path component must not be longer than MAX_PATH (260), see
2965 # https://docs.microsoft.com/en-us/windows/win32/fileio/filesystem-functionality-comparison#limits
2966 if self.oTstDrv.fpApiVer >= 6.1 \
2967 and oTestVm.sKind not in ('WindowsNT4', 'Windows2000', 'WindowsXP', 'Windows2003'):
2968 sEndMarker = '--end-marker';
2969 if oTestVm.isWindows() \
2970 or oTestVm.isOS2():
2971 sCmd = sShell;
2972 else:
2973 sCmd = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'echo');
2974
2975 for _ in xrange(0, 16):
2976 if oTestVm.isWindows() \
2977 or oTestVm.isOS2():
2978 asArgs = [ sShell, sShellOpt, "echo" ];
2979 else:
2980 asArgs = [ sCmd ];
2981
2982 # Append a random number of arguments with random length.
2983 for _ in xrange(0, self.oTestFiles.oRandom.randrange(1, 16)):
2984 asArgs.append(self.oTestFiles.generateFilenameEx((16 * 1024) - len(str(sEndMarker)), 1));
2985
2986 asArgs.append(sEndMarker);
2987
2988 reporter.log2('asArgs=%s (%d args), type=%s' % (limitString(asArgs), len(asArgs), type(asArgs)));
2989
2990 ## @todo Check limits; on Ubuntu with 256KB IPRT returns VERR_NOT_IMPLEMENTED.
2991 # Use a higher timeout (15 min) than usual for these long checks.
2992 atExec.append([ tdTestExec(sCmd, asArgs,
2993 afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut,
2994 vboxcon.ProcessCreateFlag_WaitForStdErr ],
2995 timeoutMS = 15 * 60 * 1000),
2996 tdTestResultExec(fRc = True) ]);
2997
2998 # Build up the final test array for the first batch.
2999 atTests = atInvalid + atExec;
3000
3001 #
3002 # First batch: One session per guest process.
3003 #
3004 reporter.log('One session per guest process ...');
3005 fRc = True;
3006 for (i, tTest) in enumerate(atTests):
3007 oCurTest = tTest[0] # type: tdTestExec
3008 oCurRes = tTest[1] # type: tdTestResultExec
3009 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3010 fRc2, oCurGuestSession = oCurTest.createSession('testGuestCtrlExec: Test #%d' % (i,));
3011 if fRc2 is not True:
3012 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
3013 break;
3014 fRc = self.gctrlExecDoTest(i, oCurTest, oCurRes, oCurGuestSession) and fRc;
3015 fRc = oCurTest.closeSession() and fRc;
3016
3017 reporter.log('Execution of all tests done, checking for stale sessions');
3018
3019 # No sessions left?
3020 try:
3021 aSessions = self.oTstDrv.oVBoxMgr.getArray(oSession.o.console.guest, 'sessions');
3022 except:
3023 fRc = reporter.errorXcpt();
3024 else:
3025 cSessions = len(aSessions);
3026 if cSessions != 0:
3027 fRc = reporter.error('Found %d stale session(s), expected 0:' % (cSessions,));
3028 for (i, aSession) in enumerate(aSessions):
3029 try: reporter.log(' Stale session #%d ("%s")' % (aSession.id, aSession.name));
3030 except: reporter.errorXcpt();
3031
3032 if fRc is not True:
3033 return (fRc, oTxsSession);
3034
3035 reporter.log('Now using one guest session for all tests ...');
3036
3037 #
3038 # Second batch: One session for *all* guest processes.
3039 #
3040
3041 # Create session.
3042 reporter.log('Creating session for all tests ...');
3043 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start, ];
3044 try:
3045 oGuest = oSession.o.console.guest;
3046 oCurGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain,
3047 'testGuestCtrlExec: One session for all tests');
3048 except:
3049 return (reporter.errorXcpt(), oTxsSession);
3050
3051 try:
3052 eWaitResult = oCurGuestSession.waitForArray(aeWaitFor, 30 * 1000);
3053 except:
3054 fRc = reporter.errorXcpt('Waiting for guest session to start failed:');
3055 else:
3056 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3057 fRc = reporter.error('Session did not start successfully, returned wait result: %d' % (eWaitResult,));
3058 else:
3059 reporter.log('Session successfully started');
3060
3061 # Do the tests within this session.
3062 for (i, tTest) in enumerate(atTests):
3063 oCurTest = tTest[0] # type: tdTestExec
3064 oCurRes = tTest[1] # type: tdTestResultExec
3065
3066 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3067 fRc = self.gctrlExecDoTest(i, oCurTest, oCurRes, oCurGuestSession);
3068 if fRc is False:
3069 break;
3070
3071 # Close the session.
3072 reporter.log2('Closing guest session ...');
3073 try:
3074 oCurGuestSession.close();
3075 oCurGuestSession = None;
3076 except:
3077 fRc = reporter.errorXcpt('Closing guest session failed:');
3078
3079 # No sessions left?
3080 reporter.log('Execution of all tests done, checking for stale sessions again');
3081 try: cSessions = len(self.oTstDrv.oVBoxMgr.getArray(oSession.o.console.guest, 'sessions'));
3082 except: fRc = reporter.errorXcpt();
3083 else:
3084 if cSessions != 0:
3085 fRc = reporter.error('Found %d stale session(s), expected 0' % (cSessions,));
3086 return (fRc, oTxsSession);
3087
3088 def threadForTestGuestCtrlSessionReboot(self, oGuestProcess):
3089 """
3090 Thread routine which waits for the stale guest process getting terminated (or some error)
3091 while the main test routine reboots the guest. It then compares the expected guest process result
3092 and logs an error if appropriate.
3093 """
3094 reporter.log('Waiting for process to get terminated at reboot ...');
3095 try:
3096 eWaitResult = oGuestProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate ], 5 * 60 * 1000);
3097 except:
3098 return reporter.errorXcpt('waitForArray failed');
3099 try:
3100 eStatus = oGuestProcess.status
3101 except:
3102 return reporter.errorXcpt('failed to get status (wait result %d)' % (eWaitResult,));
3103
3104 if eWaitResult == vboxcon.ProcessWaitResult_Terminate and eStatus == vboxcon.ProcessStatus_Down:
3105 reporter.log('Stale process was correctly terminated (status: down)');
3106 return True;
3107
3108 return reporter.error('Process wait across reboot failed: eWaitResult=%d, expected %d; eStatus=%d, expected %d'
3109 % (eWaitResult, vboxcon.ProcessWaitResult_Terminate, eStatus, vboxcon.ProcessStatus_Down,));
3110
3111 def testGuestCtrlSessionReboot(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
3112 """
3113 Tests guest object notifications when a guest gets rebooted / shutdown.
3114
3115 These notifications gets sent from the guest sessions in order to make API clients
3116 aware of guest session changes.
3117
3118 To test that we create a stale guest process and trigger a reboot of the guest.
3119 """
3120
3121 ## @todo backport fixes to 6.0 and maybe 5.2
3122 if self.oTstDrv.fpApiVer <= 6.0:
3123 reporter.log('Skipping: Required fixes not yet backported!');
3124 return None;
3125
3126 # Use credential defaults.
3127 oCreds = tdCtxCreds();
3128 oCreds.applyDefaultsIfNotSet(oTestVm);
3129
3130 fRc = True;
3131
3132 #
3133 # Start a session.
3134 #
3135 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
3136 try:
3137 oGuest = oSession.o.console.guest;
3138 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionReboot");
3139 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
3140 except:
3141 return (reporter.errorXcpt(), oTxsSession);
3142
3143 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
3144 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3145 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
3146 reporter.log('Session successfully started');
3147
3148 #
3149 # Create a process.
3150 #
3151 sImage = self.oTstDrv.getGuestSystemShell(oTestVm);
3152 asArgs = [ sImage, ];
3153 aEnv = [];
3154 afFlags = [];
3155 try:
3156 oGuestProcess = oGuestSession.processCreate(sImage,
3157 asArgs if self.oTstDrv.fpApiVer >= 5.0 else asArgs[1:], aEnv, afFlags,
3158 30 * 1000);
3159 except:
3160 fRc = reporter.error('Failed to start shell process (%s)' % (sImage,));
3161 else:
3162 try:
3163 eWaitResult = oGuestProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3164 except:
3165 fRc = reporter.errorXcpt('Waiting for shell process (%s) to start failed' % (sImage,));
3166 else:
3167 # Check the result and state:
3168 try: eStatus = oGuestProcess.status;
3169 except: fRc = reporter.errorXcpt('Waiting for shell process (%s) to start failed' % (sImage,));
3170 else:
3171 reporter.log2('Starting process wait result returned: %d; Process status is: %d' % (eWaitResult, eStatus,));
3172 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3173 fRc = reporter.error('wait for ProcessWaitForFlag_Start failed: %d, expected %d (Start)'
3174 % (eWaitResult, vboxcon.ProcessWaitResult_Start,));
3175 elif eStatus != vboxcon.ProcessStatus_Started:
3176 fRc = reporter.error('Unexpected process status after startup: %d, wanted %d (Started)'
3177 % (eStatus, vboxcon.ProcessStatus_Started,));
3178 else:
3179 # Create a thread that waits on the process to terminate
3180 reporter.log('Creating reboot thread ...');
3181 oThreadReboot = threading.Thread(target = self.threadForTestGuestCtrlSessionReboot,
3182 args = (oGuestProcess,),
3183 name = ('threadForTestGuestCtrlSessionReboot'));
3184 oThreadReboot.setDaemon(True);
3185 oThreadReboot.start();
3186
3187 # Not sure why this fudge is needed...
3188 reporter.log('5 second wait fudge before triggering reboot ...');
3189 self.oTstDrv.sleep(5);
3190
3191 # Do the reboot.
3192 reporter.log('Rebooting guest and reconnecting TXS ...');
3193 (oSession, oTxsSession) = self.oTstDrv.txsRebootAndReconnectViaTcp(oSession, oTxsSession,
3194 cMsTimeout = 3 * 60000);
3195 if not oSession or not oTxsSession:
3196 try: oGuestProcess.terminate();
3197 except: reporter.logXcpt();
3198 fRc = False;
3199
3200 reporter.log('Waiting for thread to finish ...');
3201 oThreadReboot.join();
3202
3203 #
3204 # Try make sure we don't leave with a stale process on failure.
3205 #
3206 try: oGuestProcess.terminate();
3207 except: reporter.logXcpt();
3208
3209 #
3210 # Close the session.
3211 #
3212 reporter.log2('Closing guest session ...');
3213 try:
3214 oGuestSession.close();
3215 except:
3216 fRc = reporter.errorXcpt();
3217
3218 return (fRc, oTxsSession);
3219
3220 def testGuestCtrlExecTimeout(self, oSession, oTxsSession, oTestVm):
3221 """
3222 Tests handling of timeouts of started guest processes.
3223 """
3224
3225 sShell = self.oTstDrv.getGuestSystemShell(oTestVm);
3226
3227 # Use credential defaults.
3228 oCreds = tdCtxCreds();
3229 oCreds.applyDefaultsIfNotSet(oTestVm);
3230
3231 #
3232 # Create a session.
3233 #
3234 try:
3235 oGuest = oSession.o.console.guest;
3236 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlExecTimeout");
3237 eWaitResult = oGuestSession.waitForArray([ vboxcon.GuestSessionWaitForFlag_Start, ], 30 * 1000);
3238 except:
3239 return (reporter.errorXcpt(), oTxsSession);
3240
3241 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
3242 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3243 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
3244 reporter.log('Session successfully started');
3245
3246 #
3247 # Create a process which never terminates and should timeout when
3248 # waiting for termination.
3249 #
3250 fRc = True;
3251 try:
3252 oCurProcess = oGuestSession.processCreate(sShell, [sShell,] if self.oTstDrv.fpApiVer >= 5.0 else [],
3253 [], [], 30 * 1000);
3254 except:
3255 fRc = reporter.errorXcpt();
3256 else:
3257 reporter.log('Waiting for process 1 being started ...');
3258 try:
3259 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3260 except:
3261 fRc = reporter.errorXcpt();
3262 else:
3263 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3264 fRc = reporter.error('Waiting for process 1 to start failed, got status %d' % (eWaitResult,));
3265 else:
3266 for msWait in (1, 32, 2000,):
3267 reporter.log('Waiting for process 1 to time out within %sms ...' % (msWait,));
3268 try:
3269 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], msWait);
3270 except:
3271 fRc = reporter.errorXcpt();
3272 break;
3273 if eWaitResult != vboxcon.ProcessWaitResult_Timeout:
3274 fRc = reporter.error('Waiting for process 1 did not time out in %sms as expected: %d'
3275 % (msWait, eWaitResult,));
3276 break;
3277 reporter.log('Waiting for process 1 timed out in %u ms, good' % (msWait,));
3278
3279 try:
3280 oCurProcess.terminate();
3281 except:
3282 reporter.errorXcpt();
3283 oCurProcess = None;
3284
3285 #
3286 # Create another process that doesn't terminate, but which will be killed by VBoxService
3287 # because it ran out of execution time (3 seconds).
3288 #
3289 try:
3290 oCurProcess = oGuestSession.processCreate(sShell, [sShell,] if self.oTstDrv.fpApiVer >= 5.0 else [],
3291 [], [], 3 * 1000);
3292 except:
3293 fRc = reporter.errorXcpt();
3294 else:
3295 reporter.log('Waiting for process 2 being started ...');
3296 try:
3297 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3298 except:
3299 fRc = reporter.errorXcpt();
3300 else:
3301 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3302 fRc = reporter.error('Waiting for process 2 to start failed, got status %d' % (eWaitResult,));
3303 else:
3304 reporter.log('Waiting for process 2 to get killed for running out of execution time ...');
3305 try:
3306 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], 15 * 1000);
3307 except:
3308 fRc = reporter.errorXcpt();
3309 else:
3310 if eWaitResult != vboxcon.ProcessWaitResult_Timeout:
3311 fRc = reporter.error('Waiting for process 2 did not time out when it should, got wait result %d'
3312 % (eWaitResult,));
3313 else:
3314 reporter.log('Waiting for process 2 did not time out, good: %s' % (eWaitResult,));
3315 try:
3316 eStatus = oCurProcess.status;
3317 except:
3318 fRc = reporter.errorXcpt();
3319 else:
3320 if eStatus != vboxcon.ProcessStatus_TimedOutKilled:
3321 fRc = reporter.error('Status of process 2 wrong; excepted %d, got %d'
3322 % (vboxcon.ProcessStatus_TimedOutKilled, eStatus));
3323 else:
3324 reporter.log('Status of process 2 is TimedOutKilled (%d) is it should be.'
3325 % (vboxcon.ProcessStatus_TimedOutKilled,));
3326 try:
3327 oCurProcess.terminate();
3328 except:
3329 reporter.logXcpt();
3330 oCurProcess = None;
3331
3332 #
3333 # Clean up the session.
3334 #
3335 try:
3336 oGuestSession.close();
3337 except:
3338 fRc = reporter.errorXcpt();
3339
3340 return (fRc, oTxsSession);
3341
3342 def testGuestCtrlDirCreate(self, oSession, oTxsSession, oTestVm):
3343 """
3344 Tests creation of guest directories.
3345 """
3346
3347 sScratch = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'testGuestCtrlDirCreate');
3348
3349 atTests = [
3350 # Invalid stuff.
3351 [ tdTestDirCreate(sDirectory = '' ), tdTestResultFailure() ],
3352 # More unusual stuff.
3353 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin('..', '.') ), tdTestResultFailure() ],
3354 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin('..', '..') ), tdTestResultFailure() ],
3355 [ tdTestDirCreate(sDirectory = '..' ), tdTestResultFailure() ],
3356 [ tdTestDirCreate(sDirectory = '../' ), tdTestResultFailure() ],
3357 [ tdTestDirCreate(sDirectory = '../../' ), tdTestResultFailure() ],
3358 [ tdTestDirCreate(sDirectory = '/' ), tdTestResultFailure() ],
3359 [ tdTestDirCreate(sDirectory = '/..' ), tdTestResultFailure() ],
3360 [ tdTestDirCreate(sDirectory = '/../' ), tdTestResultFailure() ],
3361 ];
3362 if oTestVm.isWindows() or oTestVm.isOS2():
3363 atTests.extend([
3364 [ tdTestDirCreate(sDirectory = 'C:\\' ), tdTestResultFailure() ],
3365 [ tdTestDirCreate(sDirectory = 'C:\\..' ), tdTestResultFailure() ],
3366 [ tdTestDirCreate(sDirectory = 'C:\\..\\' ), tdTestResultFailure() ],
3367 [ tdTestDirCreate(sDirectory = 'C:/' ), tdTestResultFailure() ],
3368 [ tdTestDirCreate(sDirectory = 'C:/.' ), tdTestResultFailure() ],
3369 [ tdTestDirCreate(sDirectory = 'C:/./' ), tdTestResultFailure() ],
3370 [ tdTestDirCreate(sDirectory = 'C:/..' ), tdTestResultFailure() ],
3371 [ tdTestDirCreate(sDirectory = 'C:/../' ), tdTestResultFailure() ],
3372 [ tdTestDirCreate(sDirectory = '\\\\uncrulez\\foo' ), tdTestResultFailure() ],
3373 ]);
3374 atTests.extend([
3375 # Existing directories and files.
3376 [ tdTestDirCreate(sDirectory = self.oTstDrv.getGuestSystemDir(oTestVm) ), tdTestResultFailure() ],
3377 [ tdTestDirCreate(sDirectory = self.oTstDrv.getGuestSystemShell(oTestVm) ), tdTestResultFailure() ],
3378 [ tdTestDirCreate(sDirectory = self.oTstDrv.getGuestSystemFileForReading(oTestVm) ), tdTestResultFailure() ],
3379 # Creating directories.
3380 [ tdTestDirCreate(sDirectory = sScratch ), tdTestResultSuccess() ],
3381 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo', 'bar', 'baz'),
3382 afFlags = (vboxcon.DirectoryCreateFlag_Parents,) ), tdTestResultSuccess() ],
3383 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo', 'bar', 'baz'),
3384 afFlags = (vboxcon.DirectoryCreateFlag_Parents,) ), tdTestResultSuccess() ],
3385 # Try format strings as directories.
3386 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo%sbar%sbaz%d' )), tdTestResultSuccess() ],
3387 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, '%f%%boo%%bar%RI32' )), tdTestResultSuccess() ],
3388 # Long random names.
3389 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(36, 28))),
3390 tdTestResultSuccess() ],
3391 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(140, 116))),
3392 tdTestResultSuccess() ],
3393 # Too long names. ASSUMES a guests has a 255 filename length limitation.
3394 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(2048, 256))),
3395 tdTestResultFailure() ],
3396 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(2048, 256))),
3397 tdTestResultFailure() ],
3398 # Missing directory in path.
3399 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo1', 'bar') ), tdTestResultFailure() ],
3400 ]);
3401
3402 fRc = True;
3403 for (i, tTest) in enumerate(atTests):
3404 oCurTest = tTest[0] # type: tdTestDirCreate
3405 oCurRes = tTest[1] # type: tdTestResult
3406 reporter.log('Testing #%d, sDirectory="%s" ...' % (i, limitString(oCurTest.sDirectory)));
3407
3408 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3409 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirCreate: Test #%d' % (i,));
3410 if fRc is False:
3411 return reporter.error('Test #%d failed: Could not create session' % (i,));
3412
3413 fRc = self.gctrlCreateDir(oCurTest, oCurRes, oCurGuestSession);
3414
3415 fRc = oCurTest.closeSession() and fRc;
3416 if fRc is False:
3417 fRc = reporter.error('Test #%d failed' % (i,));
3418
3419 return (fRc, oTxsSession);
3420
3421 def testGuestCtrlDirCreateTemp(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
3422 """
3423 Tests creation of temporary directories.
3424 """
3425
3426 sSystemDir = self.oTstDrv.getGuestSystemDir(oTestVm);
3427 atTests = [
3428 # Invalid stuff (template must have one or more trailin 'X'es (upper case only), or a cluster of three or more).
3429 [ tdTestDirCreateTemp(sDirectory = ''), tdTestResultFailure() ],
3430 [ tdTestDirCreateTemp(sDirectory = sSystemDir, fMode = 1234), tdTestResultFailure() ],
3431 [ tdTestDirCreateTemp(sTemplate = 'xXx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3432 [ tdTestDirCreateTemp(sTemplate = 'xxx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3433 [ tdTestDirCreateTemp(sTemplate = 'XXx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3434 [ tdTestDirCreateTemp(sTemplate = 'bar', sDirectory = 'whatever', fMode = 0o700), tdTestResultFailure() ],
3435 [ tdTestDirCreateTemp(sTemplate = 'foo', sDirectory = 'it is not used', fMode = 0o700), tdTestResultFailure() ],
3436 [ tdTestDirCreateTemp(sTemplate = 'X,so', sDirectory = 'pointless test', fMode = 0o700), tdTestResultFailure() ],
3437 # Non-existing stuff.
3438 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX',
3439 sDirectory = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'non', 'existing')),
3440 tdTestResultFailure() ],
3441 # Working stuff:
3442 [ tdTestDirCreateTemp(sTemplate = 'X', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3443 [ tdTestDirCreateTemp(sTemplate = 'XX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3444 [ tdTestDirCreateTemp(sTemplate = 'XXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3445 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
3446 tdTestResultFailure() ],
3447 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
3448 tdTestResultFailure() ],
3449 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
3450 tdTestResultFailure() ],
3451 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
3452 tdTestResultFailure() ],
3453 ## @todo test fSecure and pass weird fMode values once these parameters are implemented in the API.
3454 ];
3455
3456 fRc = True;
3457 for (i, tTest) in enumerate(atTests):
3458 oCurTest = tTest[0] # type: tdTestDirCreateTemp
3459 oCurRes = tTest[1] # type: tdTestResult
3460 reporter.log('Testing #%d, sTemplate="%s", fMode=%#o, path="%s", secure="%s" ...' %
3461 (i, oCurTest.sTemplate, oCurTest.fMode, oCurTest.sDirectory, oCurTest.fSecure));
3462
3463 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3464 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirCreateTemp: Test #%d' % (i,));
3465 if fRc is False:
3466 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
3467 break;
3468
3469 sDirTemp = '';
3470 try:
3471 sDirTemp = oCurGuestSession.directoryCreateTemp(oCurTest.sTemplate, oCurTest.fMode,
3472 oCurTest.sDirectory, oCurTest.fSecure);
3473 except:
3474 if oCurRes.fRc is True:
3475 fRc = reporter.errorXcpt('Creating temp directory "%s" failed:' % (oCurTest.sDirectory,));
3476 else:
3477 reporter.logXcpt('Creating temp directory "%s" failed expectedly, skipping:' % (oCurTest.sDirectory,));
3478 else:
3479 reporter.log2('Temporary directory is: "%s"' % (limitString(sDirTemp),));
3480 if not sDirTemp:
3481 fRc = reporter.error('Resulting directory is empty!');
3482 else:
3483 ## @todo This does not work for some unknown reason.
3484 #try:
3485 # if self.oTstDrv.fpApiVer >= 5.0:
3486 # fExists = oCurGuestSession.directoryExists(sDirTemp, False);
3487 # else:
3488 # fExists = oCurGuestSession.directoryExists(sDirTemp);
3489 #except:
3490 # fRc = reporter.errorXcpt('sDirTemp=%s' % (sDirTemp,));
3491 #else:
3492 # if fExists is not True:
3493 # fRc = reporter.error('Test #%d failed: Temporary directory "%s" does not exists (%s)'
3494 # % (i, sDirTemp, fExists));
3495 try:
3496 oFsObjInfo = oCurGuestSession.fsObjQueryInfo(sDirTemp, False);
3497 eType = oFsObjInfo.type;
3498 except:
3499 fRc = reporter.errorXcpt('sDirTemp="%s"' % (sDirTemp,));
3500 else:
3501 reporter.log2('%s: eType=%s (dir=%d)' % (limitString(sDirTemp), eType, vboxcon.FsObjType_Directory,));
3502 if eType != vboxcon.FsObjType_Directory:
3503 fRc = reporter.error('Temporary directory "%s" not created as a directory: eType=%d'
3504 % (sDirTemp, eType));
3505 fRc = oCurTest.closeSession() and fRc;
3506 return (fRc, oTxsSession);
3507
3508 def testGuestCtrlDirRead(self, oSession, oTxsSession, oTestVm):
3509 """
3510 Tests opening and reading (enumerating) guest directories.
3511 """
3512
3513 sSystemDir = self.oTstDrv.getGuestSystemDir(oTestVm);
3514 atTests = [
3515 # Invalid stuff.
3516 [ tdTestDirRead(sDirectory = ''), tdTestResultDirRead() ],
3517 [ tdTestDirRead(sDirectory = sSystemDir, afFlags = [ 1234 ]), tdTestResultDirRead() ],
3518 [ tdTestDirRead(sDirectory = sSystemDir, sFilter = '*.foo'), tdTestResultDirRead() ],
3519 # Non-existing stuff.
3520 [ tdTestDirRead(sDirectory = oTestVm.pathJoin(sSystemDir, 'really-no-such-subdir')), tdTestResultDirRead() ],
3521 [ tdTestDirRead(sDirectory = oTestVm.pathJoin(sSystemDir, 'non', 'existing')), tdTestResultDirRead() ],
3522 ];
3523
3524 if oTestVm.isWindows() or oTestVm.isOS2():
3525 atTests.extend([
3526 # More unusual stuff.
3527 [ tdTestDirRead(sDirectory = 'z:\\'), tdTestResultDirRead() ],
3528 [ tdTestDirRead(sDirectory = '\\\\uncrulez\\foo'), tdTestResultDirRead() ],
3529 ]);
3530
3531 # Read the system directory (ASSUMES at least 5 files in it):
3532 # Windows 7+ has inaccessible system32/com/dmp directory that screws up this test, so skip it on windows:
3533 if not oTestVm.isWindows():
3534 atTests.append([ tdTestDirRead(sDirectory = sSystemDir),
3535 tdTestResultDirRead(fRc = True, cFiles = -5, cDirs = None) ]);
3536 ## @todo trailing slash
3537
3538 # Read from the test file set.
3539 atTests.extend([
3540 [ tdTestDirRead(sDirectory = self.oTestFiles.oEmptyDir.sPath),
3541 tdTestResultDirRead(fRc = True, cFiles = 0, cDirs = 0, cOthers = 0) ],
3542 [ tdTestDirRead(sDirectory = self.oTestFiles.oManyDir.sPath),
3543 tdTestResultDirRead(fRc = True, cFiles = len(self.oTestFiles.oManyDir.aoChildren), cDirs = 0, cOthers = 0) ],
3544 [ tdTestDirRead(sDirectory = self.oTestFiles.oTreeDir.sPath),
3545 tdTestResultDirRead(fRc = True, cFiles = self.oTestFiles.cTreeFiles, cDirs = self.oTestFiles.cTreeDirs,
3546 cOthers = self.oTestFiles.cTreeOthers) ],
3547 ]);
3548
3549
3550 fRc = True;
3551 for (i, tTest) in enumerate(atTests):
3552 oCurTest = tTest[0] # type: tdTestExec
3553 oCurRes = tTest[1] # type: tdTestResultDirRead
3554
3555 reporter.log('Testing #%d, dir="%s" ...' % (i, oCurTest.sDirectory));
3556 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3557 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirRead: Test #%d' % (i,));
3558 if fRc is not True:
3559 break;
3560 (fRc2, cDirs, cFiles, cOthers) = self.gctrlReadDirTree(oCurTest, oCurGuestSession, oCurRes.fRc);
3561 fRc = oCurTest.closeSession() and fRc;
3562
3563 reporter.log2('Test #%d: Returned %d directories, %d files total' % (i, cDirs, cFiles));
3564 if fRc2 is oCurRes.fRc:
3565 if fRc2 is True:
3566 if oCurRes.cFiles is None:
3567 pass; # ignore
3568 elif oCurRes.cFiles >= 0 and cFiles != oCurRes.cFiles:
3569 fRc = reporter.error('Test #%d failed: Got %d files, expected %d' % (i, cFiles, oCurRes.cFiles));
3570 elif oCurRes.cFiles < 0 and cFiles < -oCurRes.cFiles:
3571 fRc = reporter.error('Test #%d failed: Got %d files, expected at least %d'
3572 % (i, cFiles, -oCurRes.cFiles));
3573 if oCurRes.cDirs is None:
3574 pass; # ignore
3575 elif oCurRes.cDirs >= 0 and cDirs != oCurRes.cDirs:
3576 fRc = reporter.error('Test #%d failed: Got %d directories, expected %d' % (i, cDirs, oCurRes.cDirs));
3577 elif oCurRes.cDirs < 0 and cDirs < -oCurRes.cDirs:
3578 fRc = reporter.error('Test #%d failed: Got %d directories, expected at least %d'
3579 % (i, cDirs, -oCurRes.cDirs));
3580 if oCurRes.cOthers is None:
3581 pass; # ignore
3582 elif oCurRes.cOthers >= 0 and cOthers != oCurRes.cOthers:
3583 fRc = reporter.error('Test #%d failed: Got %d other types, expected %d' % (i, cOthers, oCurRes.cOthers));
3584 elif oCurRes.cOthers < 0 and cOthers < -oCurRes.cOthers:
3585 fRc = reporter.error('Test #%d failed: Got %d other types, expected at least %d'
3586 % (i, cOthers, -oCurRes.cOthers));
3587
3588 else:
3589 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc));
3590
3591
3592 #
3593 # Go over a few directories in the test file set and compare names,
3594 # types and sizes rather than just the counts like we did above.
3595 #
3596 if fRc is True:
3597 oCurTest = tdTestDirRead();
3598 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3599 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirRead: gctrlReadDirTree2');
3600 if fRc is True:
3601 for oDir in (self.oTestFiles.oEmptyDir, self.oTestFiles.oManyDir, self.oTestFiles.oTreeDir):
3602 reporter.log('Checking "%s" ...' % (oDir.sPath,));
3603 fRc = self.gctrlReadDirTree2(oCurGuestSession, oDir) and fRc;
3604 fRc = oCurTest.closeSession() and fRc;
3605
3606 return (fRc, oTxsSession);
3607
3608
3609 def testGuestCtrlFileRemove(self, oSession, oTxsSession, oTestVm):
3610 """
3611 Tests removing guest files.
3612 """
3613
3614 #
3615 # Create a directory with a few files in it using TXS that we'll use for the initial tests.
3616 #
3617 asTestDirs = [
3618 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1'), # [0]
3619 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1', 'subdir-1'), # [1]
3620 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1', 'subdir-1', 'subsubdir-1'), # [2]
3621 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2'), # [3]
3622 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2', 'subdir-2'), # [4]
3623 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2', 'subdir-2', 'subsbudir-2'), # [5]
3624 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-3'), # [6]
3625 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-4'), # [7]
3626 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-5'), # [8]
3627 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-5', 'subdir-5'), # [9]
3628 ]
3629 asTestFiles = [
3630 oTestVm.pathJoin(asTestDirs[0], 'file-0'), # [0]
3631 oTestVm.pathJoin(asTestDirs[0], 'file-1'), # [1]
3632 oTestVm.pathJoin(asTestDirs[0], 'file-2'), # [2]
3633 oTestVm.pathJoin(asTestDirs[1], 'file-3'), # [3] - subdir-1
3634 oTestVm.pathJoin(asTestDirs[1], 'file-4'), # [4] - subdir-1
3635 oTestVm.pathJoin(asTestDirs[2], 'file-5'), # [5] - subsubdir-1
3636 oTestVm.pathJoin(asTestDirs[3], 'file-6'), # [6] - rmtestdir-2
3637 oTestVm.pathJoin(asTestDirs[4], 'file-7'), # [7] - subdir-2
3638 oTestVm.pathJoin(asTestDirs[5], 'file-8'), # [8] - subsubdir-2
3639 ];
3640 for sDir in asTestDirs:
3641 if oTxsSession.syncMkDir(sDir, 0o777) is not True:
3642 return reporter.error('Failed to create test dir "%s"!' % (sDir,));
3643 for sFile in asTestFiles:
3644 if oTxsSession.syncUploadString(sFile, sFile, 0o666) is not True:
3645 return reporter.error('Failed to create test file "%s"!' % (sFile,));
3646
3647 #
3648 # Tear down the directories and files.
3649 #
3650 aoTests = [
3651 # Negative tests first:
3652 tdTestRemoveFile(asTestDirs[0], fRcExpect = False),
3653 tdTestRemoveDir(asTestDirs[0], fRcExpect = False),
3654 tdTestRemoveDir(asTestFiles[0], fRcExpect = False),
3655 tdTestRemoveFile(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-file'), fRcExpect = False),
3656 tdTestRemoveDir(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir'), fRcExpect = False),
3657 tdTestRemoveFile(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir', 'no-file'), fRcExpect = False),
3658 tdTestRemoveDir(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir', 'no-subdir'), fRcExpect = False),
3659 tdTestRemoveTree(asTestDirs[0], afFlags = [], fRcExpect = False), # Only removes empty dirs, this isn't empty.
3660 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_None,], fRcExpect = False), # ditto
3661 # Empty paths:
3662 tdTestRemoveFile('', fRcExpect = False),
3663 tdTestRemoveDir('', fRcExpect = False),
3664 tdTestRemoveTree('', fRcExpect = False),
3665 # Now actually remove stuff:
3666 tdTestRemoveDir(asTestDirs[7], fRcExpect = True),
3667 tdTestRemoveFile(asTestDirs[6], fRcExpect = False),
3668 tdTestRemoveDir(asTestDirs[6], fRcExpect = True),
3669 tdTestRemoveFile(asTestFiles[0], fRcExpect = True),
3670 tdTestRemoveFile(asTestFiles[0], fRcExpect = False),
3671 # 17:
3672 tdTestRemoveTree(asTestDirs[8], fRcExpect = True), # Removes empty subdirs and leaves the dir itself.
3673 tdTestRemoveDir(asTestDirs[8], fRcExpect = True),
3674 tdTestRemoveTree(asTestDirs[3], fRcExpect = False), # Have subdirs & files,
3675 tdTestRemoveTree(asTestDirs[3], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentOnly,], fRcExpect = True),
3676 tdTestRemoveDir(asTestDirs[3], fRcExpect = True),
3677 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentAndDir,], fRcExpect = True),
3678 # No error if already delete (RTDirRemoveRecursive artifact).
3679 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentAndDir,], fRcExpect = True),
3680 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentOnly,],
3681 fNotExist = True, fRcExpect = True),
3682 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_None,], fNotExist = True, fRcExpect = True),
3683 ];
3684
3685 #
3686 # Execution loop
3687 #
3688 fRc = True;
3689 for (i, oTest) in enumerate(aoTests): # int, tdTestRemoveBase
3690 reporter.log('Testing #%d, path="%s" %s ...' % (i, oTest.sPath, oTest.__class__.__name__));
3691 oTest.setEnvironment(oSession, oTxsSession, oTestVm);
3692 fRc, _ = oTest.createSession('testGuestCtrlFileRemove: Test #%d' % (i,));
3693 if fRc is False:
3694 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
3695 break;
3696 fRc = oTest.execute(self) and fRc;
3697 fRc = oTest.closeSession() and fRc;
3698
3699 if fRc is True:
3700 oCurTest = tdTestDirRead();
3701 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3702 fRc, oCurGuestSession = oCurTest.createSession('remove final');
3703 if fRc is True:
3704
3705 #
3706 # Delete all the files in the many subdir of the test set.
3707 #
3708 reporter.log('Deleting the file in "%s" ...' % (self.oTestFiles.oManyDir.sPath,));
3709 for oFile in self.oTestFiles.oManyDir.aoChildren:
3710 reporter.log2('"%s"' % (limitString(oFile.sPath),));
3711 try:
3712 if self.oTstDrv.fpApiVer >= 5.0:
3713 oCurGuestSession.fsObjRemove(oFile.sPath);
3714 else:
3715 oCurGuestSession.fileRemove(oFile.sPath);
3716 except:
3717 fRc = reporter.errorXcpt('Removing "%s" failed' % (oFile.sPath,));
3718
3719 # Remove the directory itself to verify that we've removed all the files in it:
3720 reporter.log('Removing the directory "%s" ...' % (self.oTestFiles.oManyDir.sPath,));
3721 try:
3722 oCurGuestSession.directoryRemove(self.oTestFiles.oManyDir.sPath);
3723 except:
3724 fRc = reporter.errorXcpt('Removing directory "%s" failed' % (self.oTestFiles.oManyDir.sPath,));
3725
3726 #
3727 # Recursively delete the entire test file tree from the root up.
3728 #
3729 # Note! On unix we cannot delete the root dir itself since it is residing
3730 # in /var/tmp where only the owner may delete it. Root is the owner.
3731 #
3732 if oTestVm.isWindows() or oTestVm.isOS2():
3733 afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentAndDir,];
3734 else:
3735 afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentOnly,];
3736 try:
3737 oProgress = oCurGuestSession.directoryRemoveRecursive(self.oTestFiles.oRoot.sPath, afFlags);
3738 except:
3739 fRc = reporter.errorXcpt('Removing tree "%s" failed' % (self.oTestFiles.oRoot.sPath,));
3740 else:
3741 oWrappedProgress = vboxwrappers.ProgressWrapper(oProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv,
3742 "remove-tree-root: %s" % (self.oTestFiles.oRoot.sPath,));
3743 reporter.log2('waiting ...')
3744 oWrappedProgress.wait();
3745 reporter.log2('isSuccess=%s' % (oWrappedProgress.isSuccess(),));
3746 if not oWrappedProgress.isSuccess():
3747 fRc = oWrappedProgress.logResult();
3748
3749 fRc = oCurTest.closeSession() and fRc;
3750
3751 return (fRc, oTxsSession);
3752
3753
3754 def testGuestCtrlFileStat(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
3755 """
3756 Tests querying file information through stat.
3757 """
3758
3759 # Basic stuff, existing stuff.
3760 aoTests = [
3761 tdTestSessionEx([
3762 tdStepStatDir('.'),
3763 tdStepStatDir('..'),
3764 tdStepStatDir(self.oTstDrv.getGuestTempDir(oTestVm)),
3765 tdStepStatDir(self.oTstDrv.getGuestSystemDir(oTestVm)),
3766 tdStepStatDirEx(self.oTestFiles.oRoot),
3767 tdStepStatDirEx(self.oTestFiles.oEmptyDir),
3768 tdStepStatDirEx(self.oTestFiles.oTreeDir),
3769 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
3770 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
3771 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
3772 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
3773 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
3774 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
3775 tdStepStatFile(self.oTstDrv.getGuestSystemFileForReading(oTestVm)),
3776 tdStepStatFile(self.oTstDrv.getGuestSystemShell(oTestVm)),
3777 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
3778 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
3779 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
3780 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
3781 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
3782 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
3783 ]),
3784 ];
3785
3786 # None existing stuff.
3787 sSysDir = self.oTstDrv.getGuestSystemDir(oTestVm);
3788 sSep = oTestVm.pathSep();
3789 aoTests += [
3790 tdTestSessionEx([
3791 tdStepStatFileNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory')),
3792 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory') + sSep),
3793 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', '.')),
3794 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', 'NoSuchFileOrSubDirectory')),
3795 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', 'NoSuchFileOrSubDirectory') + sSep),
3796 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', 'NoSuchFileOrSubDirectory', '.')),
3797 #tdStepStatPathNotFound('N:\\'), # ASSUMES nothing mounted on N:!
3798 #tdStepStatPathNotFound('\\\\NoSuchUncServerName\\NoSuchShare'),
3799 ]),
3800 ];
3801 # Invalid parameter check.
3802 aoTests += [ tdTestSessionEx([ tdStepStat('', vbox.ComError.E_INVALIDARG), ]), ];
3803
3804 #
3805 # Execute the tests.
3806 #
3807 fRc, oTxsSession = tdTestSessionEx.executeListTestSessions(aoTests, self.oTstDrv, oSession, oTxsSession,
3808 oTestVm, 'FsStat');
3809 #
3810 # Test the full test file set.
3811 #
3812 if self.oTstDrv.fpApiVer < 5.0:
3813 return (fRc, oTxsSession);
3814
3815 oTest = tdTestGuestCtrlBase();
3816 oTest.setEnvironment(oSession, oTxsSession, oTestVm);
3817 fRc2, oGuestSession = oTest.createSession('FsStat on TestFileSet');
3818 if fRc2 is not True:
3819 return (False, oTxsSession);
3820
3821 for sPath in self.oTestFiles.dPaths:
3822 oFsObj = self.oTestFiles.dPaths[sPath];
3823 reporter.log2('testGuestCtrlFileStat: %s sPath=%s'
3824 % ('file' if isinstance(oFsObj, testfileset.TestFile) else 'dir ', limitString(oFsObj.sPath),));
3825
3826 # Query the information:
3827 try:
3828 oFsInfo = oGuestSession.fsObjQueryInfo(oFsObj.sPath, False);
3829 except:
3830 fRc = reporter.errorXcpt('sPath=%s type=%s: fsObjQueryInfo trouble!' % (oFsObj.sPath, type(oFsObj),));
3831 continue;
3832 if oFsInfo is None:
3833 fRc = reporter.error('sPath=%s type=%s: No info object returned!' % (oFsObj.sPath, type(oFsObj),));
3834 continue;
3835
3836 # Check attributes:
3837 try:
3838 eType = oFsInfo.type;
3839 cbObject = oFsInfo.objectSize;
3840 except:
3841 fRc = reporter.errorXcpt('sPath=%s type=%s: attribute access trouble!' % (oFsObj.sPath, type(oFsObj),));
3842 continue;
3843
3844 if isinstance(oFsObj, testfileset.TestFile):
3845 if eType != vboxcon.FsObjType_File:
3846 fRc = reporter.error('sPath=%s type=file: eType=%s, expected %s!'
3847 % (oFsObj.sPath, eType, vboxcon.FsObjType_File));
3848 if cbObject != oFsObj.cbContent:
3849 fRc = reporter.error('sPath=%s type=file: cbObject=%s, expected %s!'
3850 % (oFsObj.sPath, cbObject, oFsObj.cbContent));
3851 fFileExists = True;
3852 fDirExists = False;
3853 elif isinstance(oFsObj, testfileset.TestDir):
3854 if eType != vboxcon.FsObjType_Directory:
3855 fRc = reporter.error('sPath=%s type=dir: eType=%s, expected %s!'
3856 % (oFsObj.sPath, eType, vboxcon.FsObjType_Directory));
3857 fFileExists = False;
3858 fDirExists = True;
3859 else:
3860 fRc = reporter.error('sPath=%s type=%s: Unexpected oFsObj type!' % (oFsObj.sPath, type(oFsObj),));
3861 continue;
3862
3863 # Check the directoryExists and fileExists results too.
3864 try:
3865 fExistsResult = oGuestSession.fileExists(oFsObj.sPath, False);
3866 except:
3867 fRc = reporter.errorXcpt('sPath=%s type=%s: fileExists trouble!' % (oFsObj.sPath, type(oFsObj),));
3868 else:
3869 if fExistsResult != fFileExists:
3870 fRc = reporter.error('sPath=%s type=%s: fileExists returned %s, expected %s!'
3871 % (oFsObj.sPath, type(oFsObj), fExistsResult, fFileExists));
3872 try:
3873 fExistsResult = oGuestSession.directoryExists(oFsObj.sPath, False);
3874 except:
3875 fRc = reporter.errorXcpt('sPath=%s type=%s: directoryExists trouble!' % (oFsObj.sPath, type(oFsObj),));
3876 else:
3877 if fExistsResult != fDirExists:
3878 fRc = reporter.error('sPath=%s type=%s: directoryExists returned %s, expected %s!'
3879 % (oFsObj.sPath, type(oFsObj), fExistsResult, fDirExists));
3880
3881 fRc = oTest.closeSession() and fRc;
3882 return (fRc, oTxsSession);
3883
3884 def testGuestCtrlFileOpen(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
3885 """
3886 Tests opening guest files.
3887 """
3888 if self.oTstDrv.fpApiVer < 5.0:
3889 reporter.log('Skipping because of pre 5.0 API');
3890 return None;
3891
3892 #
3893 # Paths.
3894 #
3895 sTempDir = self.oTstDrv.getGuestTempDir(oTestVm);
3896 sFileForReading = self.oTstDrv.getGuestSystemFileForReading(oTestVm);
3897 asFiles = [
3898 oTestVm.pathJoin(sTempDir, 'file-open-0'),
3899 oTestVm.pathJoin(sTempDir, 'file-open-1'),
3900 oTestVm.pathJoin(sTempDir, 'file-open-2'),
3901 oTestVm.pathJoin(sTempDir, 'file-open-3'),
3902 oTestVm.pathJoin(sTempDir, 'file-open-4'),
3903 ];
3904 asNonEmptyFiles = [
3905 oTestVm.pathJoin(sTempDir, 'file-open-10'),
3906 oTestVm.pathJoin(sTempDir, 'file-open-11'),
3907 oTestVm.pathJoin(sTempDir, 'file-open-12'),
3908 oTestVm.pathJoin(sTempDir, 'file-open-13'),
3909 ];
3910 sContent = 'abcdefghijklmnopqrstuvwxyz0123456789';
3911 for sFile in asNonEmptyFiles:
3912 if oTxsSession.syncUploadString(sContent, sFile, 0o666) is not True:
3913 return reporter.error('Failed to create "%s" via TXS' % (sFile,));
3914
3915 #
3916 # The tests.
3917 #
3918 atTests = [
3919 # Invalid stuff.
3920 [ tdTestFileOpen(sFile = ''), tdTestResultFailure() ],
3921 # Wrong open mode.
3922 [ tdTestFileOpen(sFile = sFileForReading, eAccessMode = -1), tdTestResultFailure() ],
3923 # Wrong disposition.
3924 [ tdTestFileOpen(sFile = sFileForReading, eAction = -1), tdTestResultFailure() ],
3925 # Non-existing file or path.
3926 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir')), tdTestResultFailure() ],
3927 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir'),
3928 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultFailure() ],
3929 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir'),
3930 eAccessMode = vboxcon.FileAccessMode_WriteOnly,
3931 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultFailure() ],
3932 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir'),
3933 eAccessMode = vboxcon.FileAccessMode_ReadWrite,
3934 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultFailure() ],
3935 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-dir', 'no-such-file')), tdTestResultFailure() ],
3936 ];
3937 if self.oTstDrv.fpApiVer > 5.2: # Fixed since 6.0.
3938 atTests.extend([
3939 # Wrong type:
3940 [ tdTestFileOpen(sFile = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3941 [ tdTestFileOpen(sFile = self.oTstDrv.getGuestSystemDir(oTestVm)), tdTestResultFailure() ],
3942 ]);
3943 atTests.extend([
3944 # O_EXCL and such:
3945 [ tdTestFileOpen(sFile = sFileForReading, eAction = vboxcon.FileOpenAction_CreateNew,
3946 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultFailure() ],
3947 [ tdTestFileOpen(sFile = sFileForReading, eAction = vboxcon.FileOpenAction_CreateNew), tdTestResultFailure() ],
3948 # Open a file.
3949 [ tdTestFileOpen(sFile = sFileForReading), tdTestResultSuccess() ],
3950 [ tdTestFileOpen(sFile = sFileForReading,
3951 eAction = vboxcon.FileOpenAction_OpenOrCreate), tdTestResultSuccess() ],
3952 # Create a new file.
3953 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_CreateNew,
3954 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3955 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_CreateNew,
3956 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultFailure() ],
3957 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_OpenExisting,
3958 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3959 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_CreateOrReplace,
3960 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3961 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_OpenOrCreate,
3962 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3963 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_OpenExistingTruncated,
3964 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3965 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_AppendOrCreate,
3966 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3967 # Open or create a new file.
3968 [ tdTestFileOpenCheckSize(sFile = asFiles[1], eAction = vboxcon.FileOpenAction_OpenOrCreate,
3969 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3970 # Create or replace a new file.
3971 [ tdTestFileOpenCheckSize(sFile = asFiles[2], eAction = vboxcon.FileOpenAction_CreateOrReplace,
3972 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3973 # Create and append to file (weird stuff).
3974 [ tdTestFileOpenCheckSize(sFile = asFiles[3], eAction = vboxcon.FileOpenAction_AppendOrCreate,
3975 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3976 [ tdTestFileOpenCheckSize(sFile = asFiles[4], eAction = vboxcon.FileOpenAction_AppendOrCreate,
3977 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
3978 # Open the non-empty files in non-destructive modes.
3979 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], cbOpenExpected = len(sContent)), tdTestResultSuccess() ],
3980 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], cbOpenExpected = len(sContent),
3981 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3982 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], cbOpenExpected = len(sContent),
3983 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
3984
3985 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], cbOpenExpected = len(sContent),
3986 eAction = vboxcon.FileOpenAction_OpenOrCreate,
3987 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3988 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], cbOpenExpected = len(sContent),
3989 eAction = vboxcon.FileOpenAction_OpenOrCreate,
3990 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
3991 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], cbOpenExpected = len(sContent),
3992 eAction = vboxcon.FileOpenAction_OpenOrCreate,
3993 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
3994
3995 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], cbOpenExpected = len(sContent),
3996 eAction = vboxcon.FileOpenAction_AppendOrCreate,
3997 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3998 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], cbOpenExpected = len(sContent),
3999 eAction = vboxcon.FileOpenAction_AppendOrCreate,
4000 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4001 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], cbOpenExpected = len(sContent),
4002 eAction = vboxcon.FileOpenAction_AppendOrCreate,
4003 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4004
4005 # Now the destructive stuff:
4006 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], eAccessMode = vboxcon.FileAccessMode_WriteOnly,
4007 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultSuccess() ],
4008 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], eAccessMode = vboxcon.FileAccessMode_WriteOnly,
4009 eAction = vboxcon.FileOpenAction_CreateOrReplace), tdTestResultSuccess() ],
4010 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], eAction = vboxcon.FileOpenAction_CreateOrReplace,
4011 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4012 ]);
4013
4014 #
4015 # Do the testing.
4016 #
4017 fRc = True;
4018 for (i, tTest) in enumerate(atTests):
4019 oCurTest = tTest[0] # type: tdTestFileOpen
4020 oCurRes = tTest[1] # type: tdTestResult
4021
4022 reporter.log('Testing #%d: %s - sFile="%s", eAccessMode=%d, eAction=%d, (%s, %s, %s) ...'
4023 % (i, oCurTest.__class__.__name__, oCurTest.sFile, oCurTest.eAccessMode, oCurTest.eAction,
4024 oCurTest.eSharing, oCurTest.fCreationMode, oCurTest.afOpenFlags,));
4025
4026 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4027 fRc, _ = oCurTest.createSession('testGuestCtrlFileOpen: Test #%d' % (i,));
4028 if fRc is not True:
4029 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4030 break;
4031
4032 fRc2 = oCurTest.doSteps(oCurRes.fRc, self);
4033 if fRc2 != oCurRes.fRc:
4034 fRc = reporter.error('Test #%d result mismatch: Got %s, expected %s' % (i, fRc2, oCurRes.fRc,));
4035
4036 fRc = oCurTest.closeSession() and fRc;
4037
4038 return (fRc, oTxsSession);
4039
4040
4041 def testGuestCtrlFileRead(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-branches,too-many-statements
4042 """
4043 Tests reading from guest files.
4044 """
4045 if self.oTstDrv.fpApiVer < 5.0:
4046 reporter.log('Skipping because of pre 5.0 API');
4047 return None;
4048
4049 #
4050 # Do everything in one session.
4051 #
4052 oTest = tdTestGuestCtrlBase();
4053 oTest.setEnvironment(oSession, oTxsSession, oTestVm);
4054 fRc2, oGuestSession = oTest.createSession('FsStat on TestFileSet');
4055 if fRc2 is not True:
4056 return (False, oTxsSession);
4057
4058 #
4059 # Create a really big zero filled, up to 1 GiB, adding it to the list of
4060 # files from the set.
4061 #
4062 # Note! This code sucks a bit because we don't have a working setSize nor
4063 # any way to figure out how much free space there is in the guest.
4064 #
4065 aoExtraFiles = [];
4066 sBigName = self.oTestFiles.generateFilenameEx();
4067 sBigPath = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, sBigName);
4068 fRc = True;
4069 try:
4070 oFile = oGuestSession.fileOpenEx(sBigPath, vboxcon.FileAccessMode_ReadWrite, vboxcon.FileOpenAction_CreateOrReplace,
4071 vboxcon.FileSharingMode_All, 0, []);
4072 except:
4073 fRc = reporter.errorXcpt('sBigName=%s' % (sBigPath,));
4074 else:
4075 # Does setSize work now?
4076 fUseFallback = True;
4077 try:
4078 oFile.setSize(0);
4079 oFile.setSize(64);
4080 fUseFallback = False;
4081 except Exception as oXcpt:
4082 reporter.logXcpt();
4083
4084 # Grow the file till we hit trouble, typical VERR_DISK_FULL, then
4085 # reduce the file size if we have a working setSize.
4086 cbBigFile = 0;
4087 while cbBigFile < (1024 + 32)*1024*1024:
4088 if not fUseFallback:
4089 cbBigFile += 16*1024*1024;
4090 try:
4091 oFile.setSize(cbBigFile);
4092 except Exception as oXcpt:
4093 reporter.logXcpt('cbBigFile=%s' % (sBigPath,));
4094 try:
4095 cbBigFile -= 16*1024*1024;
4096 oFile.setSize(cbBigFile);
4097 except:
4098 reporter.logXcpt('cbBigFile=%s' % (sBigPath,));
4099 break;
4100 else:
4101 cbBigFile += 32*1024*1024;
4102 try:
4103 oFile.seek(cbBigFile, vboxcon.FileSeekOrigin_Begin);
4104 oFile.write(bytearray(1), 60*1000);
4105 except:
4106 reporter.logXcpt('cbBigFile=%s' % (sBigPath,));
4107 break;
4108 try:
4109 cbBigFile = oFile.seek(0, vboxcon.FileSeekOrigin_End);
4110 except:
4111 fRc = reporter.errorXcpt('sBigName=%s' % (sBigPath,));
4112 try:
4113 oFile.close();
4114 except:
4115 fRc = reporter.errorXcpt('sBigName=%s' % (sBigPath,));
4116 if fRc is True:
4117 reporter.log('Big file: %s bytes: %s' % (cbBigFile, sBigPath,));
4118 aoExtraFiles.append(testfileset.TestFileZeroFilled(None, sBigPath, cbBigFile));
4119 else:
4120 try:
4121 oGuestSession.fsObjRemove(sBigPath);
4122 except:
4123 reporter.errorXcpt('fsObjRemove(sBigName=%s)' % (sBigPath,));
4124
4125 #
4126 # Open and read all the files in the test file set.
4127 #
4128 for oTestFile in aoExtraFiles + self.oTestFiles.aoFiles: # type: testfileset.TestFile
4129 reporter.log2('Test file: %s bytes, "%s" ...' % (oTestFile.cbContent, limitString(oTestFile.sPath),));
4130
4131 #
4132 # Open it:
4133 #
4134 try:
4135 oFile = oGuestSession.fileOpenEx(oTestFile.sPath, vboxcon.FileAccessMode_ReadOnly,
4136 vboxcon.FileOpenAction_OpenExisting, vboxcon.FileSharingMode_All, 0, []);
4137 except:
4138 fRc = reporter.errorXcpt('sPath=%s' % (oTestFile.sPath, ));
4139 continue;
4140
4141 #
4142 # Read the file in different sized chunks:
4143 #
4144 if oTestFile.cbContent < 128:
4145 acbChunks = xrange(1,128);
4146 elif oTestFile.cbContent < 1024:
4147 acbChunks = (2048, 127, 63, 32, 29, 17, 16, 15, 9);
4148 elif oTestFile.cbContent < 8*1024*1024:
4149 acbChunks = (128*1024, 32*1024, 8191, 255);
4150 else:
4151 acbChunks = (768*1024, 128*1024);
4152
4153 for cbChunk in acbChunks:
4154 # Read the whole file straight thru:
4155 #if oTestFile.cbContent >= 1024*1024: reporter.log2('... cbChunk=%s' % (cbChunk,));
4156 offFile = 0;
4157 cReads = 0;
4158 while offFile <= oTestFile.cbContent:
4159 try:
4160 abRead = oFile.read(cbChunk, 30*1000);
4161 except:
4162 fRc = reporter.errorXcpt('%s: offFile=%s cbChunk=%s cbContent=%s'
4163 % (oTestFile.sPath, offFile, cbChunk, oTestFile.cbContent));
4164 break;
4165 cbRead = len(abRead);
4166 if cbRead == 0 and offFile == oTestFile.cbContent:
4167 break;
4168 if cbRead <= 0:
4169 fRc = reporter.error('%s @%s: cbRead=%s, cbContent=%s'
4170 % (oTestFile.sPath, offFile, cbRead, oTestFile.cbContent));
4171 break;
4172 if not oTestFile.equalMemory(abRead, offFile):
4173 fRc = reporter.error('%s: read mismatch @ %s LB %s' % (oTestFile.sPath, offFile, cbRead));
4174 break;
4175 offFile += cbRead;
4176 cReads += 1;
4177 if cReads > 8192:
4178 break;
4179
4180 # Seek to start of file.
4181 try:
4182 offFile = oFile.seek(0, vboxcon.FileSeekOrigin_Begin);
4183 except:
4184 fRc = reporter.errorXcpt('%s: error seeking to start of file' % (oTestFile.sPath,));
4185 break;
4186 if offFile != 0:
4187 fRc = reporter.error('%s: seek to start of file returned %u, expected 0' % (oTestFile.sPath, offFile));
4188 break;
4189
4190 #
4191 # Random reads.
4192 #
4193 for _ in xrange(8):
4194 offFile = self.oTestFiles.oRandom.randrange(0, oTestFile.cbContent + 1024);
4195 cbToRead = self.oTestFiles.oRandom.randrange(1, min(oTestFile.cbContent + 256, 768*1024));
4196 #if oTestFile.cbContent >= 1024*1024: reporter.log2('... %s LB %s' % (offFile, cbToRead,));
4197
4198 try:
4199 offActual = oFile.seek(offFile, vboxcon.FileSeekOrigin_Begin);
4200 except:
4201 fRc = reporter.errorXcpt('%s: error seeking to %s' % (oTestFile.sPath, offFile));
4202 break;
4203 if offActual != offFile:
4204 fRc = reporter.error('%s: seek(%s,Begin) -> %s, expected %s'
4205 % (oTestFile.sPath, offFile, offActual, offFile));
4206 break;
4207
4208 try:
4209 abRead = oFile.read(cbToRead, 30*1000);
4210 except:
4211 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s'
4212 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4213 cbRead = 0;
4214 else:
4215 cbRead = len(abRead);
4216 if not oTestFile.equalMemory(abRead, offFile):
4217 fRc = reporter.error('%s: random read mismatch @ %s LB %s' % (oTestFile.sPath, offFile, cbRead,));
4218
4219 try:
4220 offActual = oFile.offset;
4221 except:
4222 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#1)'
4223 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4224 else:
4225 if offActual != offFile + cbRead:
4226 fRc = reporter.error('%s: IFile.offset is %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#1)'
4227 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4228 try:
4229 offActual = oFile.seek(0, vboxcon.FileSeekOrigin_Current);
4230 except:
4231 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#1)'
4232 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4233 else:
4234 if offActual != offFile + cbRead:
4235 fRc = reporter.error('%s: seek(0,cur) -> %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#1)'
4236 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4237
4238 #
4239 # Random reads using readAt.
4240 #
4241 for _ in xrange(12):
4242 offFile = self.oTestFiles.oRandom.randrange(0, oTestFile.cbContent + 1024);
4243 cbToRead = self.oTestFiles.oRandom.randrange(1, min(oTestFile.cbContent + 256, 768*1024));
4244 #if oTestFile.cbContent >= 1024*1024: reporter.log2('... %s LB %s (readAt)' % (offFile, cbToRead,));
4245
4246 try:
4247 abRead = oFile.readAt(offFile, cbToRead, 30*1000);
4248 except:
4249 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s'
4250 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4251 cbRead = 0;
4252 else:
4253 cbRead = len(abRead);
4254 if not oTestFile.equalMemory(abRead, offFile):
4255 fRc = reporter.error('%s: random readAt mismatch @ %s LB %s' % (oTestFile.sPath, offFile, cbRead,));
4256
4257 try:
4258 offActual = oFile.offset;
4259 except:
4260 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#2)'
4261 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4262 else:
4263 if offActual != offFile + cbRead:
4264 fRc = reporter.error('%s: IFile.offset is %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#2)'
4265 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4266
4267 try:
4268 offActual = oFile.seek(0, vboxcon.FileSeekOrigin_Current);
4269 except:
4270 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#2)'
4271 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4272 else:
4273 if offActual != offFile + cbRead:
4274 fRc = reporter.error('%s: seek(0,cur) -> %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#2)'
4275 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4276
4277 #
4278 # A few negative things.
4279 #
4280
4281 # Zero byte reads -> E_INVALIDARG.
4282 try:
4283 abRead = oFile.read(0, 30*1000);
4284 except Exception as oXcpt:
4285 if vbox.ComError.notEqual(oXcpt, vbox.ComError.E_INVALIDARG):
4286 fRc = reporter.errorXcpt('read(0,30s) did not raise E_INVALIDARG as expected!');
4287 else:
4288 fRc = reporter.error('read(0,30s) did not fail!');
4289
4290 try:
4291 abRead = oFile.readAt(0, 0, 30*1000);
4292 except Exception as oXcpt:
4293 if vbox.ComError.notEqual(oXcpt, vbox.ComError.E_INVALIDARG):
4294 fRc = reporter.errorXcpt('readAt(0,0,30s) did not raise E_INVALIDARG as expected!');
4295 else:
4296 fRc = reporter.error('readAt(0,0,30s) did not fail!');
4297
4298 # See what happens when we read 1GiB. We should get a max of 1MiB back.
4299 ## @todo Document this behaviour in VirtualBox.xidl.
4300 try:
4301 oFile.seek(0, vboxcon.FileSeekOrigin_Begin);
4302 except:
4303 fRc = reporter.error('seek(0)');
4304 try:
4305 abRead = oFile.read(1024*1024*1024, 30*1000);
4306 except:
4307 fRc = reporter.errorXcpt('read(1GiB,30s)');
4308 else:
4309 if len(abRead) != min(oTestFile.cbContent, 1024*1024):
4310 fRc = reporter.error('Expected read(1GiB,30s) to return %s bytes, got %s bytes instead'
4311 % (min(oTestFile.cbContent, 1024*1024), len(abRead),));
4312
4313 try:
4314 abRead = oFile.readAt(0, 1024*1024*1024, 30*1000);
4315 except:
4316 fRc = reporter.errorXcpt('readAt(0,1GiB,30s)');
4317 else:
4318 if len(abRead) != min(oTestFile.cbContent, 1024*1024):
4319 reporter.error('Expected readAt(0, 1GiB,30s) to return %s bytes, got %s bytes instead'
4320 % (min(oTestFile.cbContent, 1024*1024), len(abRead),));
4321
4322 #
4323 # Check stat info on the file as well as querySize.
4324 #
4325 if self.oTstDrv.fpApiVer > 5.2:
4326 try:
4327 oFsObjInfo = oFile.queryInfo();
4328 except:
4329 fRc = reporter.errorXcpt('%s: queryInfo()' % (oTestFile.sPath,));
4330 else:
4331 if oFsObjInfo is None:
4332 fRc = reporter.error('IGuestFile::queryInfo returned None');
4333 else:
4334 try:
4335 cbFile = oFsObjInfo.objectSize;
4336 except:
4337 fRc = reporter.errorXcpt();
4338 else:
4339 if cbFile != oTestFile.cbContent:
4340 fRc = reporter.error('%s: queryInfo returned incorrect file size: %s, expected %s'
4341 % (oTestFile.sPath, cbFile, oTestFile.cbContent));
4342
4343 try:
4344 cbFile = oFile.querySize();
4345 except:
4346 fRc = reporter.errorXcpt('%s: querySize()' % (oTestFile.sPath,));
4347 else:
4348 if cbFile != oTestFile.cbContent:
4349 fRc = reporter.error('%s: querySize returned incorrect file size: %s, expected %s'
4350 % (oTestFile.sPath, cbFile, oTestFile.cbContent));
4351
4352 #
4353 # Use seek to test the file size and do a few other end-relative seeks.
4354 #
4355 try:
4356 cbFile = oFile.seek(0, vboxcon.FileSeekOrigin_End);
4357 except:
4358 fRc = reporter.errorXcpt('%s: seek(0,End)' % (oTestFile.sPath,));
4359 else:
4360 if cbFile != oTestFile.cbContent:
4361 fRc = reporter.error('%s: seek(0,End) returned incorrect file size: %s, expected %s'
4362 % (oTestFile.sPath, cbFile, oTestFile.cbContent));
4363 if oTestFile.cbContent > 0:
4364 for _ in xrange(5):
4365 offSeek = self.oTestFiles.oRandom.randrange(oTestFile.cbContent + 1);
4366 try:
4367 offFile = oFile.seek(-offSeek, vboxcon.FileSeekOrigin_End);
4368 except:
4369 fRc = reporter.errorXcpt('%s: seek(%s,End)' % (oTestFile.sPath, -offSeek,));
4370 else:
4371 if offFile != oTestFile.cbContent - offSeek:
4372 fRc = reporter.error('%s: seek(%s,End) returned incorrect offset: %s, expected %s (cbContent=%s)'
4373 % (oTestFile.sPath, -offSeek, offSeek, oTestFile.cbContent - offSeek,
4374 oTestFile.cbContent,));
4375
4376 #
4377 # Close it and we're done with this file.
4378 #
4379 try:
4380 oFile.close();
4381 except:
4382 fRc = reporter.errorXcpt('%s: error closing the file' % (oTestFile.sPath,));
4383
4384 #
4385 # Clean up.
4386 #
4387 for oTestFile in aoExtraFiles:
4388 try:
4389 oGuestSession.fsObjRemove(sBigPath);
4390 except:
4391 fRc = reporter.errorXcpt('fsObjRemove(%s)' % (sBigPath,));
4392
4393 fRc = oTest.closeSession() and fRc;
4394
4395 return (fRc, oTxsSession);
4396
4397
4398 def testGuestCtrlFileWrite(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
4399 """
4400 Tests writing to guest files.
4401 """
4402 if self.oTstDrv.fpApiVer < 5.0:
4403 reporter.log('Skipping because of pre 5.0 API');
4404 return None;
4405
4406 #
4407 # The test file and its content.
4408 #
4409 sFile = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'gctrl-write-1');
4410 abContent = bytearray(0);
4411
4412 #
4413 # The tests.
4414 #
4415 def randBytes(cbHowMany):
4416 """ Returns an bytearray of random bytes. """
4417 return bytearray(self.oTestFiles.oRandom.getrandbits(8) for _ in xrange(cbHowMany));
4418
4419 aoTests = [
4420 # Write at end:
4421 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_CreateNew, abContent = abContent,
4422 atChunks = [(None, randBytes(1)), (None, randBytes(77)), (None, randBytes(98)),]),
4423 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 1+77+98), # 176
4424 # Appending:
4425 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_AppendOrCreate, abContent = abContent,
4426 atChunks = [(None, randBytes(255)), (None, randBytes(33)),]),
4427 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 176 + 255+33), # 464
4428 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_AppendOrCreate, abContent = abContent,
4429 atChunks = [(10, randBytes(44)),]),
4430 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 464 + 44), # 508
4431 # Write within existing:
4432 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_OpenExisting, abContent = abContent,
4433 atChunks = [(0, randBytes(1)), (50, randBytes(77)), (255, randBytes(199)),]),
4434 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 508),
4435 # Writing around and over the end:
4436 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent,
4437 atChunks = [(500, randBytes(9)), (508, randBytes(15)), (512, randBytes(12)),]),
4438 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 512+12),
4439
4440 # writeAt appending:
4441 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True,
4442 atChunks = [(0, randBytes(23)), (6, randBytes(1018)),]),
4443 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 6+1018), # 1024
4444 # writeAt within existing:
4445 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True,
4446 atChunks = [(1000, randBytes(23)), (1, randBytes(990)),]),
4447 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 1024),
4448 # writeAt around and over the end:
4449 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True,
4450 atChunks = [(1024, randBytes(63)), (1080, randBytes(968)),]),
4451 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 1080+968), # 2048
4452
4453 # writeAt beyond the end (gap is filled with zeros):
4454 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True, atChunks = [(3070, randBytes(2)),]),
4455 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 3072),
4456 # write beyond the end (gap is filled with zeros):
4457 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, atChunks = [(4090, randBytes(6)),]),
4458 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 4096),
4459 ];
4460
4461 for (i, oCurTest) in enumerate(aoTests):
4462 reporter.log('Testing #%d: %s ...' % (i, oCurTest.toString(),));
4463
4464 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4465 fRc, _ = oCurTest.createSession('testGuestCtrlFileWrite: Test #%d' % (i,));
4466 if fRc is not True:
4467 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4468 break;
4469
4470 fRc2 = oCurTest.doSteps(True, self);
4471 if fRc2 is not True:
4472 fRc = reporter.error('Test #%d failed!' % (i,));
4473
4474 fRc = oCurTest.closeSession() and fRc;
4475
4476 #
4477 # Cleanup
4478 #
4479 if oTxsSession.syncRmFile(sFile) is not True:
4480 fRc = reporter.error('Failed to remove write-test file: %s' % (sFile, ));
4481
4482 return (fRc, oTxsSession);
4483
4484 @staticmethod
4485 def __generateFile(sName, cbFile):
4486 """ Helper for generating a file with a given size. """
4487 oFile = open(sName, 'wb');
4488 while cbFile > 0:
4489 cb = cbFile if cbFile < 256*1024 else 256*1024;
4490 oFile.write(bytearray(random.getrandbits(8) for _ in xrange(cb)));
4491 cbFile -= cb;
4492 oFile.close();
4493
4494 def testGuestCtrlCopyTo(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
4495 """
4496 Tests copying files from host to the guest.
4497 """
4498
4499 #
4500 # Paths and test files.
4501 #
4502 sScratchHst = os.path.join(self.oTstDrv.sScratchPath, 'copyto');
4503 sScratchTestFilesHst = os.path.join(sScratchHst, self.oTestFiles.sSubDir);
4504 sScratchEmptyDirHst = os.path.join(sScratchTestFilesHst, self.oTestFiles.oEmptyDir.sName);
4505 sScratchNonEmptyDirHst = self.oTestFiles.chooseRandomDirFromTree().buildPath(sScratchHst, os.path.sep);
4506 sScratchTreeDirHst = os.path.join(sScratchTestFilesHst, self.oTestFiles.oTreeDir.sName);
4507
4508 sScratchGst = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'copyto');
4509 sScratchDstDir1Gst = oTestVm.pathJoin(sScratchGst, 'dstdir1');
4510 sScratchDstDir2Gst = oTestVm.pathJoin(sScratchGst, 'dstdir2');
4511 sScratchDstDir3Gst = oTestVm.pathJoin(sScratchGst, 'dstdir3');
4512 sScratchDstDir4Gst = oTestVm.pathJoin(sScratchGst, 'dstdir4');
4513 #sScratchGstNotExist = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'no-such-file-or-directory');
4514 sScratchHstNotExist = os.path.join(self.oTstDrv.sScratchPath, 'no-such-file-or-directory');
4515 sScratchGstPathNotFound = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'no-such-directory', 'or-file');
4516 #sScratchHstPathNotFound = os.path.join(self.oTstDrv.sScratchPath, 'no-such-directory', 'or-file');
4517
4518 if oTestVm.isWindows() or oTestVm.isOS2():
4519 sScratchGstInvalid = "?*|<invalid-name>";
4520 else:
4521 sScratchGstInvalid = None;
4522 if utils.getHostOs() in ('win', 'os2'):
4523 sScratchHstInvalid = "?*|<invalid-name>";
4524 else:
4525 sScratchHstInvalid = None;
4526
4527 for sDir in (sScratchGst, sScratchDstDir1Gst, sScratchDstDir2Gst, sScratchDstDir3Gst, sScratchDstDir4Gst):
4528 if oTxsSession.syncMkDir(sDir, 0o777) is not True:
4529 return reporter.error('TXS failed to create directory "%s"!' % (sDir,));
4530
4531 # Put the test file set under sScratchHst.
4532 if os.path.exists(sScratchHst):
4533 if base.wipeDirectory(sScratchHst) != 0:
4534 return reporter.error('Failed to wipe "%s"' % (sScratchHst,));
4535 else:
4536 try:
4537 os.mkdir(sScratchHst);
4538 except:
4539 return reporter.errorXcpt('os.mkdir(%s)' % (sScratchHst, ));
4540 if self.oTestFiles.writeToDisk(sScratchHst) is not True:
4541 return reporter.error('Filed to write test files to "%s" on the host!' % (sScratchHst,));
4542
4543 # Generate a test file in 32MB to 64 MB range.
4544 sBigFileHst = os.path.join(self.oTstDrv.sScratchPath, 'gctrl-random.data');
4545 cbBigFileHst = random.randrange(32*1024*1024, 64*1024*1024);
4546 reporter.log('cbBigFileHst=%s' % (cbBigFileHst,));
4547 cbLeft = cbBigFileHst;
4548 try:
4549 self.__generateFile(sBigFileHst, cbBigFileHst);
4550 except:
4551 return reporter.errorXcpt('sBigFileHst=%s cbBigFileHst=%s cbLeft=%s' % (sBigFileHst, cbBigFileHst, cbLeft,));
4552 reporter.log('cbBigFileHst=%s' % (cbBigFileHst,));
4553
4554 # Generate an empty file on the host that we can use to save space in the guest.
4555 sEmptyFileHst = os.path.join(self.oTstDrv.sScratchPath, 'gctrl-empty.data');
4556 try:
4557 oFile = open(sEmptyFileHst, "wb");
4558 oFile.close();
4559 except:
4560 return reporter.errorXcpt('sEmptyFileHst=%s' % (sEmptyFileHst,));
4561
4562 #
4563 # Tests.
4564 #
4565 atTests = [
4566 # Nothing given:
4567 [ tdTestCopyToFile(), tdTestResultFailure() ],
4568 [ tdTestCopyToDir(), tdTestResultFailure() ],
4569 # Only source given:
4570 [ tdTestCopyToFile(sSrc = sBigFileHst), tdTestResultFailure() ],
4571 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst), tdTestResultFailure() ],
4572 # Only destination given:
4573 [ tdTestCopyToFile(sDst = oTestVm.pathJoin(sScratchGst, 'dstfile')), tdTestResultFailure() ],
4574 [ tdTestCopyToDir( sDst = sScratchGst), tdTestResultFailure() ],
4575 # Both given, but invalid flags.
4576 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGst, afFlags = [ 0x40000000] ), tdTestResultFailure() ],
4577 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst, sDst = sScratchGst, afFlags = [ 0x40000000] ),
4578 tdTestResultFailure() ],
4579 ];
4580 atTests.extend([
4581 # Non-existing source, but no destination:
4582 [ tdTestCopyToFile(sSrc = sScratchHstNotExist), tdTestResultFailure() ],
4583 [ tdTestCopyToDir( sSrc = sScratchHstNotExist), tdTestResultFailure() ],
4584 # Valid sources, but destination path not found:
4585 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGstPathNotFound), tdTestResultFailure() ],
4586 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst, sDst = sScratchGstPathNotFound), tdTestResultFailure() ],
4587 # Valid destination, but source file/dir not found:
4588 [ tdTestCopyToFile(sSrc = sScratchHstNotExist, sDst = oTestVm.pathJoin(sScratchGst, 'dstfile')),
4589 tdTestResultFailure() ],
4590 [ tdTestCopyToDir( sSrc = sScratchHstNotExist, sDst = sScratchGst), tdTestResultFailure() ],
4591 # Wrong type:
4592 [ tdTestCopyToFile(sSrc = sScratchEmptyDirHst, sDst = oTestVm.pathJoin(sScratchGst, 'dstfile')),
4593 tdTestResultFailure() ],
4594 [ tdTestCopyToDir( sSrc = sBigFileHst, sDst = sScratchGst), tdTestResultFailure() ],
4595 ]);
4596 # Invalid characters in destination or source path:
4597 if sScratchGstInvalid is not None:
4598 atTests.extend([
4599 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, sScratchGstInvalid)),
4600 tdTestResultFailure() ],
4601 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst, sDst = oTestVm.pathJoin(sScratchGst, sScratchGstInvalid)),
4602 tdTestResultFailure() ],
4603 ]);
4604 if sScratchHstInvalid is not None:
4605 atTests.extend([
4606 [ tdTestCopyToFile(sSrc = os.path.join(self.oTstDrv.sScratchPath, sScratchHstInvalid), sDst = sScratchGst),
4607 tdTestResultFailure() ],
4608 [ tdTestCopyToDir( sSrc = os.path.join(self.oTstDrv.sScratchPath, sScratchHstInvalid), sDst = sScratchGst),
4609 tdTestResultFailure() ],
4610 ]);
4611
4612 #
4613 # Single file handling.
4614 #
4615 atTests.extend([
4616 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat')),
4617 tdTestResultSuccess() ],
4618 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat')), # Overwrite
4619 tdTestResultSuccess() ],
4620 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat')), # Overwrite
4621 tdTestResultSuccess() ],
4622 ]);
4623 if self.oTstDrv.fpApiVer > 5.2: # Copying files into directories via Main is supported only 6.0 and later.
4624 atTests.extend([
4625 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGst), tdTestResultSuccess() ],
4626 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGst), tdTestResultSuccess() ], # Overwrite
4627 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = oTestVm.pathJoin(sScratchGst, os.path.split(sBigFileHst)[1])),
4628 tdTestResultSuccess() ], # Overwrite
4629 ]);
4630
4631 if oTestVm.isWindows():
4632 # Copy to a Windows alternative data stream (ADS).
4633 atTests.extend([
4634 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat:ADS-Test')),
4635 tdTestResultSuccess() ],
4636 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat:ADS-Test')),
4637 tdTestResultSuccess() ],
4638 ]);
4639
4640 #
4641 # Directory handling.
4642 #
4643 if self.oTstDrv.fpApiVer > 5.2: # Copying directories via Main is supported only in versions > 5.2.
4644 atTests.extend([
4645 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir1Gst,
4646 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4647 # Try again.
4648 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir1Gst,
4649 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4650 # Should fail, as destination directory already exists.
4651 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir1Gst), tdTestResultFailure() ],
4652 # Try again with trailing slash, should yield the same result:
4653 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir2Gst + oTestVm.pathSep(),
4654 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4655 # Try again.
4656 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir2Gst + oTestVm.pathSep(),
4657 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4658 # Should fail, as destination directory already exists.
4659 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir2Gst + oTestVm.pathSep()),
4660 tdTestResultFailure() ],
4661 # Copy with a different destination name just for the heck of it:
4662 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = oTestVm.pathJoin(sScratchDstDir1Gst, 'empty2')),
4663 tdTestResultSuccess() ],
4664 ]);
4665 atTests.extend([
4666 # Now the same using a directory with files in it:
4667 [ tdTestCopyToDir(sSrc = sScratchNonEmptyDirHst, sDst = sScratchDstDir3Gst,
4668 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4669 # Again.
4670 [ tdTestCopyToDir(sSrc = sScratchNonEmptyDirHst, sDst = sScratchDstDir3Gst,
4671 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4672 # Should fail, as directory is existing already.
4673 [ tdTestCopyToDir(sSrc = sScratchNonEmptyDirHst, sDst = sScratchDstDir3Gst), tdTestResultFailure() ],
4674 ]);
4675 atTests.extend([
4676 # Copy the entire test tree:
4677 [ tdTestCopyToDir(sSrc = sScratchTreeDirHst, sDst = sScratchDstDir4Gst,
4678 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4679 ]);
4680
4681 fRc = True;
4682 for (i, tTest) in enumerate(atTests):
4683 oCurTest = tTest[0]; # tdTestCopyTo
4684 oCurRes = tTest[1]; # tdTestResult
4685 reporter.log('Testing #%d, sSrc=%s, sDst=%s, afFlags=%s ...'
4686 % (i, limitString(oCurTest.sSrc), limitString(oCurTest.sDst), oCurTest.afFlags));
4687
4688 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4689 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlCopyTo: Test #%d' % (i,));
4690 if fRc is not True:
4691 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4692 break;
4693
4694 fRc2 = False;
4695 if isinstance(oCurTest, tdTestCopyToFile):
4696 fRc2 = self.gctrlCopyFileTo(oCurGuestSession, oCurTest.sSrc, oCurTest.sDst, oCurTest.afFlags, oCurRes.fRc);
4697 else:
4698 fRc2 = self.gctrlCopyDirTo(oCurGuestSession, oCurTest.sSrc, oCurTest.sDst, oCurTest.afFlags, oCurRes.fRc);
4699 if fRc2 is not oCurRes.fRc:
4700 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc));
4701
4702 fRc = oCurTest.closeSession() and fRc;
4703
4704 return (fRc, oTxsSession);
4705
4706 def testGuestCtrlCopyFrom(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
4707 """
4708 Tests copying files from guest to the host.
4709 """
4710
4711 #
4712 # Paths.
4713 #
4714 sScratchHst = os.path.join(self.oTstDrv.sScratchPath, "testGctrlCopyFrom");
4715 sScratchDstDir1Hst = os.path.join(sScratchHst, "dstdir1");
4716 sScratchDstDir2Hst = os.path.join(sScratchHst, "dstdir2");
4717 sScratchDstDir3Hst = os.path.join(sScratchHst, "dstdir3");
4718 oExistingFileGst = self.oTestFiles.chooseRandomFile();
4719 oNonEmptyDirGst = self.oTestFiles.chooseRandomDirFromTree(fNonEmpty = True);
4720 oEmptyDirGst = self.oTestFiles.oEmptyDir;
4721
4722 if oTestVm.isWindows() or oTestVm.isOS2():
4723 sScratchGstInvalid = "?*|<invalid-name>";
4724 else:
4725 sScratchGstInvalid = None;
4726 if utils.getHostOs() in ('win', 'os2'):
4727 sScratchHstInvalid = "?*|<invalid-name>";
4728 else:
4729 sScratchHstInvalid = None;
4730
4731 if os.path.exists(sScratchHst):
4732 if base.wipeDirectory(sScratchHst) != 0:
4733 return reporter.error('Failed to wipe "%s"' % (sScratchHst,));
4734 else:
4735 try:
4736 os.mkdir(sScratchHst);
4737 except:
4738 return reporter.errorXcpt('os.mkdir(%s)' % (sScratchHst, ));
4739
4740 for sSubDir in (sScratchDstDir1Hst, sScratchDstDir2Hst, sScratchDstDir3Hst):
4741 try:
4742 os.mkdir(sSubDir);
4743 except:
4744 return reporter.errorXcpt('os.mkdir(%s)' % (sSubDir, ));
4745
4746 #
4747 # Bad parameter tests.
4748 #
4749 atTests = [
4750 # Missing both source and destination:
4751 [ tdTestCopyFromFile(), tdTestResultFailure() ],
4752 [ tdTestCopyFromDir(), tdTestResultFailure() ],
4753 # Missing source.
4754 [ tdTestCopyFromFile(sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
4755 [ tdTestCopyFromDir( sDst = sScratchHst), tdTestResultFailure() ],
4756 # Missing destination.
4757 [ tdTestCopyFromFile(oSrc = oExistingFileGst), tdTestResultFailure() ],
4758 [ tdTestCopyFromDir( sSrc = self.oTestFiles.oManyDir.sPath), tdTestResultFailure() ],
4759 # Invalid flags:
4760 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'somefile'), afFlags = [0x40000000]),
4761 tdTestResultFailure() ],
4762 [ tdTestCopyFromDir( oSrc = oEmptyDirGst, sDst = os.path.join(sScratchHst, 'somedir'), afFlags = [ 0x40000000] ),
4763 tdTestResultFailure() ],
4764 # Non-existing sources:
4765 [ tdTestCopyFromFile(sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-file-or-directory'),
4766 sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
4767 [ tdTestCopyFromDir( sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-file-or-directory'),
4768 sDst = os.path.join(sScratchHst, 'somedir')), tdTestResultFailure() ],
4769 [ tdTestCopyFromFile(sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-directory', 'no-such-file'),
4770 sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
4771 [ tdTestCopyFromDir( sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-directory', 'no-such-subdir'),
4772 sDst = os.path.join(sScratchHst, 'somedir')), tdTestResultFailure() ],
4773 # Non-existing destinations:
4774 [ tdTestCopyFromFile(oSrc = oExistingFileGst,
4775 sDst = os.path.join(sScratchHst, 'no-such-directory', 'somefile') ), tdTestResultFailure() ],
4776 [ tdTestCopyFromDir( oSrc = oEmptyDirGst, sDst = os.path.join(sScratchHst, 'no-such-directory', 'somedir') ),
4777 tdTestResultFailure() ],
4778 [ tdTestCopyFromFile(oSrc = oExistingFileGst,
4779 sDst = os.path.join(sScratchHst, 'no-such-directory-slash' + os.path.sep)),
4780 tdTestResultFailure() ],
4781 # Wrong source type:
4782 [ tdTestCopyFromFile(oSrc = oNonEmptyDirGst, sDst = os.path.join(sScratchHst, 'somefile') ), tdTestResultFailure() ],
4783 [ tdTestCopyFromDir(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'somedir') ), tdTestResultFailure() ],
4784 ];
4785 # Bogus names:
4786 if sScratchHstInvalid:
4787 atTests.extend([
4788 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, sScratchHstInvalid)),
4789 tdTestResultFailure() ],
4790 [ tdTestCopyFromDir( sSrc = self.oTestFiles.oManyDir.sPath, sDst = os.path.join(sScratchHst, sScratchHstInvalid)),
4791 tdTestResultFailure() ],
4792 ]);
4793 if sScratchGstInvalid:
4794 atTests.extend([
4795 [ tdTestCopyFromFile(sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, sScratchGstInvalid),
4796 sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
4797 [ tdTestCopyFromDir( sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, sScratchGstInvalid),
4798 sDst = os.path.join(sScratchHst, 'somedir')), tdTestResultFailure() ],
4799 ]);
4800
4801 #
4802 # Single file copying.
4803 #
4804 atTests.extend([
4805 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'copyfile1')),
4806 tdTestResultSuccess() ],
4807 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'copyfile1')), # Overwrite it
4808 tdTestResultSuccess() ],
4809 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'copyfile2')),
4810 tdTestResultSuccess() ],
4811 ]);
4812 if self.oTstDrv.fpApiVer > 5.2:
4813 # Copy into a directory.
4814 atTests.extend([
4815 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = sScratchHst), tdTestResultSuccess() ],
4816 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = sScratchHst + os.path.sep), tdTestResultSuccess() ],
4817 ]);
4818
4819 #
4820 # Directory tree copying:
4821 #
4822 atTests.extend([
4823 # Copy the empty guest directory (should end up as sScratchHst/empty):
4824 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir1Hst), tdTestResultSuccess() ],
4825 # Repeat -- this time it should fail, as the destination directory already exists (and
4826 # DirectoryCopyFlag_CopyIntoExisting is not specified):
4827 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir1Hst), tdTestResultFailure() ],
4828 # Add the DirectoryCopyFlag_CopyIntoExisting flag being set and it should work.
4829 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir1Hst,
4830 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
4831 # Try again with trailing slash, should yield the same result:
4832 [ tdTestRemoveHostDir(os.path.join(sScratchDstDir1Hst, 'empty')), tdTestResult() ],
4833 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir1Hst + os.path.sep),
4834 tdTestResultSuccess() ],
4835 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir1Hst + os.path.sep),
4836 tdTestResultFailure() ],
4837 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir1Hst + os.path.sep,
4838 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
4839 # Copy with a different destination name just for the heck of it:
4840 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = os.path.join(sScratchHst, 'empty2'), fIntoDst = True),
4841 tdTestResultFailure() ],
4842 # Now the same using a directory with files in it:
4843 [ tdTestCopyFromDir(oSrc = oNonEmptyDirGst, sDst = sScratchDstDir2Hst), tdTestResultSuccess() ],
4844 [ tdTestCopyFromDir(oSrc = oNonEmptyDirGst, sDst = sScratchDstDir2Hst), tdTestResultFailure() ],
4845 [ tdTestCopyFromDir(oSrc = oNonEmptyDirGst, sDst = sScratchDstDir2Hst,
4846 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
4847 # Copy the entire test tree:
4848 [ tdTestCopyFromDir(sSrc = self.oTestFiles.oTreeDir.sPath, sDst = sScratchDstDir3Hst), tdTestResultSuccess() ],
4849 ]);
4850
4851 #
4852 # Execute the tests.
4853 #
4854 fRc = True;
4855 for (i, tTest) in enumerate(atTests):
4856 oCurTest = tTest[0]
4857 oCurRes = tTest[1] # type: tdTestResult
4858 if isinstance(oCurTest, tdTestCopyFrom):
4859 reporter.log('Testing #%d, %s: sSrc="%s", sDst="%s", afFlags="%s" ...'
4860 % (i, "directory" if isinstance(oCurTest, tdTestCopyFromDir) else "file",
4861 limitString(oCurTest.sSrc), limitString(oCurTest.sDst), oCurTest.afFlags,));
4862 else:
4863 reporter.log('Testing #%d, tdTestRemoveHostDir "%s" ...' % (i, oCurTest.sDir,));
4864 if isinstance(oCurTest, tdTestCopyFromDir) and self.oTstDrv.fpApiVer < 6.0:
4865 reporter.log('Skipping directoryCopyFromGuest test, not implemented in %s' % (self.oTstDrv.fpApiVer,));
4866 continue;
4867
4868 if isinstance(oCurTest, tdTestRemoveHostDir):
4869 fRc = oCurTest.execute(self.oTstDrv, oSession, oTxsSession, oTestVm, 'testing #%d' % (i,));
4870 else:
4871 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4872 fRc2, oCurGuestSession = oCurTest.createSession('testGuestCtrlCopyFrom: Test #%d' % (i,));
4873 if fRc2 is not True:
4874 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4875 break;
4876
4877 if isinstance(oCurTest, tdTestCopyFromFile):
4878 fRc2 = self.gctrlCopyFileFrom(oCurGuestSession, oCurTest, oCurRes.fRc);
4879 else:
4880 fRc2 = self.gctrlCopyDirFrom(oCurGuestSession, oCurTest, oCurRes.fRc);
4881
4882 if fRc2 != oCurRes.fRc:
4883 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc));
4884
4885 fRc = oCurTest.closeSession() and fRc;
4886
4887 return (fRc, oTxsSession);
4888
4889 def testGuestCtrlUpdateAdditions(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
4890 """
4891 Tests updating the Guest Additions inside the guest.
4892
4893 """
4894
4895 ## @todo currently disabled everywhere.
4896 if self.oTstDrv.fpApiVer < 100.0:
4897 reporter.log("Skipping updating GAs everywhere for now...");
4898 return None;
4899
4900 # Skip test for updating Guest Additions if we run on a too old (Windows) guest.
4901 ##
4902 ## @todo make it work everywhere!
4903 ##
4904 if oTestVm.sKind in ('WindowsNT4', 'Windows2000', 'WindowsXP', 'Windows2003'):
4905 reporter.log("Skipping updating GAs on old windows vm (sKind=%s)" % (oTestVm.sKind,));
4906 return (None, oTxsSession);
4907 if oTestVm.isOS2():
4908 reporter.log("Skipping updating GAs on OS/2 guest");
4909 return (None, oTxsSession);
4910
4911 sVBoxValidationKitIso = self.oTstDrv.sVBoxValidationKitIso;
4912 if not os.path.isfile(sVBoxValidationKitIso):
4913 return reporter.log('Validation Kit .ISO not found at "%s"' % (sVBoxValidationKitIso,));
4914
4915 sScratch = os.path.join(self.oTstDrv.sScratchPath, "testGctrlUpdateAdditions");
4916 try:
4917 os.makedirs(sScratch);
4918 except OSError as e:
4919 if e.errno != errno.EEXIST:
4920 return reporter.error('Failed: Unable to create scratch directory \"%s\"' % (sScratch,));
4921 reporter.log('Scratch path is: %s' % (sScratch,));
4922
4923 atTests = [];
4924 if oTestVm.isWindows():
4925 atTests.extend([
4926 # Source is missing.
4927 [ tdTestUpdateAdditions(sSrc = ''), tdTestResultFailure() ],
4928
4929 # Wrong flags.
4930 [ tdTestUpdateAdditions(sSrc = self.oTstDrv.getGuestAdditionsIso(),
4931 afFlags = [ 1234 ]), tdTestResultFailure() ],
4932
4933 # Non-existing .ISO.
4934 [ tdTestUpdateAdditions(sSrc = "non-existing.iso"), tdTestResultFailure() ],
4935
4936 # Wrong .ISO.
4937 [ tdTestUpdateAdditions(sSrc = sVBoxValidationKitIso), tdTestResultFailure() ],
4938
4939 # The real thing.
4940 [ tdTestUpdateAdditions(sSrc = self.oTstDrv.getGuestAdditionsIso()),
4941 tdTestResultSuccess() ],
4942 # Test the (optional) installer arguments. This will extract the
4943 # installer into our guest's scratch directory.
4944 [ tdTestUpdateAdditions(sSrc = self.oTstDrv.getGuestAdditionsIso(),
4945 asArgs = [ '/extract', '/D=' + sScratch ]),
4946 tdTestResultSuccess() ]
4947 # Some debg ISO. Only enable locally.
4948 #[ tdTestUpdateAdditions(
4949 # sSrc = "V:\\Downloads\\VBoxGuestAdditions-r80354.iso"),
4950 # tdTestResultSuccess() ]
4951 ]);
4952 else:
4953 reporter.log('No OS-specific tests for non-Windows yet!');
4954
4955 fRc = True;
4956 for (i, tTest) in enumerate(atTests):
4957 oCurTest = tTest[0] # type: tdTestUpdateAdditions
4958 oCurRes = tTest[1] # type: tdTestResult
4959 reporter.log('Testing #%d, sSrc="%s", afFlags="%s" ...' % (i, oCurTest.sSrc, oCurTest.afFlags,));
4960
4961 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4962 fRc, _ = oCurTest.createSession('Test #%d' % (i,));
4963 if fRc is not True:
4964 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4965 break;
4966
4967 try:
4968 oCurProgress = oCurTest.oGuest.updateGuestAdditions(oCurTest.sSrc, oCurTest.asArgs, oCurTest.afFlags);
4969 except:
4970 reporter.maybeErrXcpt(oCurRes.fRc, 'Updating Guest Additions exception for sSrc="%s", afFlags="%s":'
4971 % (oCurTest.sSrc, oCurTest.afFlags,));
4972 fRc = False;
4973 else:
4974 if oCurProgress is not None:
4975 oWrapperProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr,
4976 self.oTstDrv, "gctrlUpGA");
4977 oWrapperProgress.wait();
4978 if not oWrapperProgress.isSuccess():
4979 oWrapperProgress.logResult(fIgnoreErrors = not oCurRes.fRc);
4980 fRc = False;
4981 else:
4982 fRc = reporter.error('No progress object returned');
4983
4984 oCurTest.closeSession();
4985 if fRc is oCurRes.fRc:
4986 if fRc:
4987 ## @todo Verify if Guest Additions were really updated (build, revision, ...).
4988 ## @todo r=bird: Not possible since you're installing the same GAs as before...
4989 ## Maybe check creation dates on certain .sys/.dll/.exe files?
4990 pass;
4991 else:
4992 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc, oCurRes.fRc));
4993 break;
4994
4995 return (fRc, oTxsSession);
4996
4997
4998
4999class tdAddGuestCtrl(vbox.TestDriver): # pylint: disable=too-many-instance-attributes,too-many-public-methods
5000 """
5001 Guest control using VBoxService on the guest.
5002 """
5003
5004 def __init__(self):
5005 vbox.TestDriver.__init__(self);
5006 self.oTestVmSet = self.oTestVmManager.getSmokeVmSet('nat');
5007 self.asRsrcs = None;
5008 self.fQuick = False; # Don't skip lengthly tests by default.
5009 self.addSubTestDriver(SubTstDrvAddGuestCtrl(self));
5010
5011 #
5012 # Overridden methods.
5013 #
5014 def showUsage(self):
5015 """
5016 Shows the testdriver usage.
5017 """
5018 rc = vbox.TestDriver.showUsage(self);
5019 reporter.log('');
5020 reporter.log('tdAddGuestCtrl Options:');
5021 reporter.log(' --quick');
5022 reporter.log(' Same as --virt-modes hwvirt --cpu-counts 1.');
5023 return rc;
5024
5025 def parseOption(self, asArgs, iArg): # pylint: disable=too-many-branches,too-many-statements
5026 """
5027 Parses the testdriver arguments from the command line.
5028 """
5029 if asArgs[iArg] == '--quick':
5030 self.parseOption(['--virt-modes', 'hwvirt'], 0);
5031 self.parseOption(['--cpu-counts', '1'], 0);
5032 self.fQuick = True;
5033 else:
5034 return vbox.TestDriver.parseOption(self, asArgs, iArg);
5035 return iArg + 1;
5036
5037 def actionConfig(self):
5038 if not self.importVBoxApi(): # So we can use the constant below.
5039 return False;
5040
5041 eNic0AttachType = vboxcon.NetworkAttachmentType_NAT;
5042 sGaIso = self.getGuestAdditionsIso();
5043 return self.oTestVmSet.actionConfig(self, eNic0AttachType = eNic0AttachType, sDvdImage = sGaIso);
5044
5045 def actionExecute(self):
5046 return self.oTestVmSet.actionExecute(self, self.testOneCfg);
5047
5048 #
5049 # Test execution helpers.
5050 #
5051 def testOneCfg(self, oVM, oTestVm): # pylint: disable=too-many-statements
5052 """
5053 Runs the specified VM thru the tests.
5054
5055 Returns a success indicator on the general test execution. This is not
5056 the actual test result.
5057 """
5058
5059 self.logVmInfo(oVM);
5060
5061 fRc = True;
5062 oSession, oTxsSession = self.startVmAndConnectToTxsViaTcp(oTestVm.sVmName, fCdWait = False);
5063 reporter.log("TxsSession: %s" % (oTxsSession,));
5064 if oSession is not None:
5065 self.addTask(oTxsSession);
5066
5067 fRc, oTxsSession = self.aoSubTstDrvs[0].testIt(oTestVm, oSession, oTxsSession);
5068
5069 # Cleanup.
5070 self.removeTask(oTxsSession);
5071 if not self.aoSubTstDrvs[0].oDebug.fNoExit:
5072 self.terminateVmBySession(oSession);
5073 else:
5074 fRc = False;
5075 return fRc;
5076
5077 def onExit(self, iRc):
5078 if self.aoSubTstDrvs[0].oDebug.fNoExit:
5079 return True
5080 return vbox.TestDriver.onExit(self, iRc);
5081
5082 def gctrlReportError(self, progress):
5083 """
5084 Helper function to report an error of a
5085 given progress object.
5086 """
5087 if progress is None:
5088 reporter.log('No progress object to print error for');
5089 else:
5090 errInfo = progress.errorInfo;
5091 if errInfo:
5092 reporter.log('%s' % (errInfo.text,));
5093 return False;
5094
5095 def gctrlGetRemainingTime(self, msTimeout, msStart):
5096 """
5097 Helper function to return the remaining time (in ms)
5098 based from a timeout value and the start time (both in ms).
5099 """
5100 if msTimeout == 0:
5101 return 0xFFFFFFFE; # Wait forever.
5102 msElapsed = base.timestampMilli() - msStart;
5103 if msElapsed > msTimeout:
5104 return 0; # No time left.
5105 return msTimeout - msElapsed;
5106
5107 def testGuestCtrlManual(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals,too-many-statements,unused-argument,unused-variable
5108 """
5109 For manually testing certain bits.
5110 """
5111
5112 reporter.log('Manual testing ...');
5113 fRc = True;
5114
5115 sUser = 'Administrator';
5116 sPassword = 'password';
5117
5118 oGuest = oSession.o.console.guest;
5119 oGuestSession = oGuest.createSession(sUser,
5120 sPassword,
5121 "", "Manual Test");
5122
5123 aWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
5124 _ = oGuestSession.waitForArray(aWaitFor, 30 * 1000);
5125
5126 sCmd = self.getGuestSystemShell(oTestVm);
5127 asArgs = [ sCmd, '/C', 'dir', '/S', 'c:\\windows' ];
5128 aEnv = [];
5129 afFlags = [];
5130
5131 for _ in xrange(100):
5132 oProc = oGuestSession.processCreate(sCmd, asArgs if self.fpApiVer >= 5.0 else asArgs[1:],
5133 aEnv, afFlags, 30 * 1000);
5134
5135 aWaitFor = [ vboxcon.ProcessWaitForFlag_Terminate ];
5136 _ = oProc.waitForArray(aWaitFor, 30 * 1000);
5137
5138 oGuestSession.close();
5139 oGuestSession = None;
5140
5141 time.sleep(5);
5142
5143 oSession.o.console.PowerDown();
5144
5145 return (fRc, oTxsSession);
5146
5147if __name__ == '__main__':
5148 sys.exit(tdAddGuestCtrl().main(sys.argv));
Note: See TracBrowser for help on using the repository browser.

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