VirtualBox

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

Last change on this file since 97439 was 97439, checked in by vboxsync, 2 years ago

Validation Kit/Guest Control: Use 'cross' when creating TestFileSet.

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

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