VirtualBox

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

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

Validation Kit/tdAddGuestCtrl.py: Check for buffer instances only with Python >= 2.7.

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