VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/tests/audio/tdAudioTest.py@ 91090

Last change on this file since 91090 was 91090, checked in by vboxsync, 3 years ago

Audio/Validation Kit: Implemented host audio probing for the test driver to detect host OSes which don't have audio (configured / enabled / whatever). ​bugref:10008

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.2 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: tdAudioTest.py 91090 2021-09-02 12:17:58Z vboxsync $
3
4"""
5AudioTest test driver which invokes the VKAT (Validation Kit Audio Test)
6binary to perform the actual audio tests.
7
8The generated test set archive on the guest will be downloaded by TXS
9to the host for later audio comparison / verification.
10"""
11
12__copyright__ = \
13"""
14Copyright (C) 2021 Oracle Corporation
15
16This file is part of VirtualBox Open Source Edition (OSE), as
17available from http://www.virtualbox.org. This file is free software;
18you can redistribute it and/or modify it under the terms of the GNU
19General Public License (GPL) as published by the Free Software
20Foundation, in version 2 as it comes in the "COPYING" file of the
21VirtualBox OSE distribution. VirtualBox OSE is distributed in the
22hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
23
24The contents of this file may alternatively be used under the terms
25of the Common Development and Distribution License Version 1.0
26(CDDL) only, as it comes in the "COPYING.CDDL" file of the
27VirtualBox OSE distribution, in which case the provisions of the
28CDDL are applicable instead of those of the GPL.
29
30You may elect to license modified versions of this file under the
31terms and conditions of either the GPL or the CDDL or both.
32"""
33__version__ = "$Revision: 91090 $"
34
35# Standard Python imports.
36import os
37import sys
38import signal
39import subprocess
40import uuid
41
42# Only the main script needs to modify the path.
43try: __file__
44except: __file__ = sys.argv[0];
45g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))));
46sys.path.append(g_ksValidationKitDir);
47
48# Validation Kit imports.
49from testdriver import reporter
50from testdriver import base
51from testdriver import vbox
52from testdriver import vboxtestvms
53from common import utils;
54
55# pylint: disable=unnecessary-semicolon
56
57class tdAudioTest(vbox.TestDriver):
58 """
59 Runs various audio tests.
60 """
61 def __init__(self):
62 vbox.TestDriver.__init__(self);
63 self.oTestVmSet = self.oTestVmManager.getSmokeVmSet('nat');
64 self.asGstVkatPaths = [
65 # Debugging stuff (SCP'd over to the guest).
66 '/tmp/vkat',
67 '/tmp/VBoxAudioTest',
68 'C:\\Temp\\vkat',
69 'C:\\Temp\\VBoxAudioTest',
70 # Validation Kit .ISO.
71 '${CDROM}/vboxvalidationkit/${OS/ARCH}/vkat${EXESUFF}',
72 '${CDROM}/${OS/ARCH}/vkat${EXESUFF}',
73 # Test VMs.
74 '/opt/apps/vkat',
75 '/opt/apps/VBoxAudioTest',
76 '/apps/vkat',
77 '/apps/VBoxAudioTest',
78 'C:\\Apps\\vkat${EXESUFF}',
79 'C:\\Apps\\VBoxAudioTest${EXESUFF}',
80 ## @odo VBoxAudioTest on Guest Additions?
81 ];
82 self.asTestsDef = [
83 'guest_tone_playback', 'guest_tone_recording'
84 ];
85 self.asTests = self.asTestsDef;
86
87 # Enable audio debug mode.
88 #
89 # This is needed in order to load and use the Validation Kit audio driver,
90 # which in turn is being used in conjunction with the guest side to record
91 # output (guest is playing back) and injecting input (guest is recording).
92 self.asOptExtraData = [
93 'VBoxInternal2/Audio/Debug/Enabled:true',
94 ];
95
96 # Name of the running VM to use for running the test driver. Optional, and None if not being used.
97 self.sRunningVmName = None;
98
99 def showUsage(self):
100 """
101 Shows the audio test driver-specific command line options.
102 """
103 fRc = vbox.TestDriver.showUsage(self);
104 reporter.log('');
105 reporter.log('tdAudioTest Options:');
106 reporter.log(' --runningvmname <vmname>');
107 reporter.log(' --audio-tests <s1[:s2[:]]>');
108 reporter.log(' Default: %s (all)' % (':'.join(self.asTestsDef)));
109 return fRc;
110
111 def parseOption(self, asArgs, iArg):
112 """
113 Parses the audio test driver-specific command line options.
114 """
115 if asArgs[iArg] == '--runningvmname':
116 iArg += 1;
117 if iArg >= len(asArgs):
118 raise base.InvalidOption('The "--runningvmname" needs VM name');
119
120 self.sRunningVmName = asArgs[iArg];
121 elif asArgs[iArg] == '--audio-tests':
122 iArg += 1;
123 if asArgs[iArg] == 'all': # Nice for debugging scripts.
124 self.asTests = self.asTestsDef;
125 else:
126 self.asTests = asArgs[iArg].split(':');
127 for s in self.asTests:
128 if s not in self.asTestsDef:
129 raise base.InvalidOption('The "--audio-tests" value "%s" is not valid; valid values are: %s'
130 % (s, ' '.join(self.asTestsDef)));
131 else:
132 return vbox.TestDriver.parseOption(self, asArgs, iArg);
133 return iArg + 1;
134
135 def actionVerify(self):
136 """
137 Verifies the test driver before running.
138 """
139 if self.sVBoxValidationKitIso is None or not os.path.isfile(self.sVBoxValidationKitIso):
140 reporter.error('Cannot find the VBoxValidationKit.iso! (%s)'
141 'Please unzip a Validation Kit build in the current directory or in some parent one.'
142 % (self.sVBoxValidationKitIso,) );
143 return False;
144 return vbox.TestDriver.actionVerify(self);
145
146 def actionConfig(self):
147 """
148 Configures the test driver before running.
149 """
150 if not self.importVBoxApi(): # So we can use the constant below.
151 return False;
152
153 # Make sure that the Validation Kit .ISO is mounted
154 # to find the VKAT (Validation Kit Audio Test) binary on it.
155 assert self.sVBoxValidationKitIso is not None;
156 return self.oTestVmSet.actionConfig(self, sDvdImage = self.sVBoxValidationKitIso);
157
158 def actionExecute(self):
159 """
160 Executes the test driver.
161 """
162 if self.sRunningVmName is None:
163 return self.oTestVmSet.actionExecute(self, self.testOneVmConfig);
164 return self.actionExecuteOnRunnigVM();
165
166 def actionExecuteOnRunnigVM(self):
167 """
168 Executes the tests in an already configured + running VM.
169 """
170 if not self.importVBoxApi():
171 return False;
172
173 fRc = True;
174
175 oVirtualBox = self.oVBoxMgr.getVirtualBox();
176 try:
177 oVM = oVirtualBox.findMachine(self.sRunningVmName);
178 if oVM.state != self.oVBoxMgr.constants.MachineState_Running:
179 reporter.error("Machine '%s' is not in Running state" % (self.sRunningVmName));
180 fRc = False;
181 except:
182 reporter.errorXcpt("Machine '%s' not found" % (self.sRunningVmName));
183 fRc = False;
184
185 if fRc:
186 oSession = self.openSession(oVM);
187 if oSession:
188 # Tweak this to your likings.
189 oTestVm = vboxtestvms.TestVm('runningvm', sKind = 'WindowsXP'); #sKind = 'WindowsXP' # sKind = 'Ubuntu_64'
190 (fRc, oTxsSession) = self.txsDoConnectViaTcp(oSession, 30 * 1000);
191 if fRc:
192 self.doTest(oTestVm, oSession, oTxsSession);
193 else:
194 reporter.error("Unable to open session for machine '%s'" % (self.sRunningVmName));
195 fRc = False;
196
197 del oVM;
198 del oVirtualBox;
199 return fRc;
200
201 def getGstVkatLogFilePath(self, oTestVm):
202 """
203 Returns the log file path of VKAT running on the guest (daemonized).
204 """
205 return oTestVm.pathJoin(self.getGuestTempDir(oTestVm), 'vkat-guest.log');
206
207 def locateGstVkat(self, oSession, oTxsSession):
208 """
209 Returns guest side path to VKAT.
210 """
211 for sVkatPath in self.asGstVkatPaths:
212 reporter.log2('Checking for VKAT at: %s ...' % (sVkatPath));
213 if self.txsIsFile(oSession, oTxsSession, sVkatPath):
214 return (True, sVkatPath);
215 reporter.error('Unable to find guest VKAT in any of these places:\n%s' % ('\n'.join(self.asGstVkatPaths),));
216 return (False, "");
217
218 def executeHstLoop(self, sWhat, asArgs, asEnv = None, fAsAdmin = False):
219 """
220 Inner loop which handles the execution of a host binary.
221 """
222 fRc = False;
223
224 asEnvTmp = os.environ.copy();
225 if asEnv:
226 for sEnv in asEnv:
227 sKey, sValue = sEnv.split('=');
228 reporter.log2('Setting env var \"%s\" -> \"%s\"' % (sKey, sValue));
229 os.environ[sKey] = sValue; # Also apply it to the current environment.
230 asEnvTmp[sKey] = sValue;
231
232 if fAsAdmin \
233 and utils.getHostOs() != 'win':
234 oProcess = utils.sudoProcessPopen(asArgs,
235 env = asEnvTmp,
236 stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = False,
237 close_fds = False);
238 else:
239 oProcess = utils.processPopenSafe(asArgs,
240 env = asEnvTmp,
241 stdout = subprocess.PIPE, stderr = subprocess.PIPE);
242 if oProcess:
243 for line in iter(oProcess.stdout.readline, b''):
244 reporter.log('[' + sWhat + '] ' + line.decode('utf-8'));
245 oProcess.communicate();
246 if oProcess.returncode == 0:
247 fRc = True;
248 else:
249 reporter.log2('Executing \"%s\" on host returned exit code error %d' % (sWhat, oProcess.returncode));
250
251 return fRc;
252
253 def executeHst(self, sWhat, asArgs, asEnv = None, fAsync = False, fAsAdmin = False):
254 """
255 Runs a binary (image) with optional admin (root) rights on the host and
256 waits until it terminates.
257
258 Windows currently is not supported yet running stuff as Administrator.
259
260 Returns success status (exit code is 0).
261 """
262 reporter.log('Executing \"%s\" on host (as admin = %s, async = %s)' % (sWhat, fAsAdmin, fAsync));
263
264 reporter.testStart(sWhat);
265
266 fRc = self.executeHstLoop(sWhat, asArgs, asEnv);
267 if fRc:
268 reporter.log('Executing \"%s\" on host done' % (sWhat,));
269 else:
270 reporter.log('Executing \"%s\" on host failed' % (sWhat,));
271
272 reporter.testDone();
273
274 return fRc;
275
276 def killHstProcessByName(self, sProcName):
277 """
278 Kills processes by their name.
279 """
280 reporter.log('Trying to kill processes named "%s"' % (sProcName,));
281 if sys.platform == 'win32':
282 sArgProcName = '\"%s.exe\"' % sProcName;
283 asArgs = [ 'taskkill', '/IM', sArgProcName, '/F' ];
284 self.executeHst('Killing process', asArgs);
285 else: # Note: killall is not available on older Debians (requires psmisc).
286 # Using the BSD syntax here; MacOS also should understand this.
287 procPs = subprocess.Popen(['ps', 'ax'], stdout=subprocess.PIPE);
288 out, err = procPs.communicate();
289 if err:
290 reporter.log('PS stderr:');
291 for sLine in err.decode('utf-8').splitlines():
292 reporter.log(sLine);
293 if out:
294 reporter.log4('PS stdout:');
295 for sLine in out.decode('utf-8').splitlines():
296 reporter.log4(sLine);
297 if sProcName in sLine:
298 pid = int(sLine.split(None, 1)[0]);
299 reporter.log('Killing PID %d' % (pid,));
300 os.kill(pid, signal.SIGKILL); # pylint: disable=no-member
301
302 def killHstVkat(self):
303 """
304 Kills VKAT (VBoxAudioTest) on the host side.
305 """
306 reporter.log('Killing stale/old VKAT processes ...');
307 self.killHstProcessByName("vkat");
308 self.killHstProcessByName("VBoxAudioTest");
309
310 def getWinFirewallArgsDisable(self, sOsType):
311 """
312 Returns the command line arguments for Windows OSes
313 to disable the built-in firewall (if any).
314
315 If not supported, returns an empty array.
316 """
317 if sOsType == 'vista': # pylint: disable=no-else-return
318 # Vista and up.
319 return (['netsh.exe', 'advfirewall', 'set', 'allprofiles', 'state', 'off']);
320 elif sOsType == 'xp': # Older stuff (XP / 2003).
321 return(['netsh.exe', 'firewall', 'set', 'opmode', 'mode=DISABLE']);
322 # Not supported / available.
323 return [];
324
325 def disableGstFirewall(self, oTestVm, oTxsSession):
326 """
327 Disables the firewall on a guest (if any).
328
329 Needs elevated / admin / root privileges.
330
331 Returns success status, not logged.
332 """
333 fRc = False;
334
335 asArgs = [];
336 sOsType = '';
337 if oTestVm.isWindows():
338 if oTestVm.sKind in ['WindowsNT4', 'WindowsNT3x']:
339 sOsType = 'nt3x'; # Not supported, but define it anyway.
340 elif oTestVm.sKind in ('Windows2000', 'WindowsXP', 'Windows2003'):
341 sOsType = 'xp';
342 else:
343 sOsType = 'vista';
344 asArgs = self.getWinFirewallArgsDisable(sOsType);
345 else:
346 sOsType = 'unsupported';
347
348 reporter.log('Disabling firewall on guest (type: %s) ...' % (sOsType,));
349
350 if asArgs:
351 fRc = self.txsRunTest(oTxsSession, 'Disabling guest firewall', 3 * 60 * 1000, \
352 oTestVm.pathJoin(self.getGuestSystemDir(oTestVm), asArgs[0]), asArgs);
353 if not fRc:
354 reporter.error('Disabling firewall on guest returned exit code error %d' % (self.getLastRcFromTxs(oTxsSession)));
355 else:
356 reporter.log('Firewall not available on guest, skipping');
357 fRc = True; # Not available, just skip.
358
359 return fRc;
360
361 def disableHstFirewall(self):
362 """
363 Disables the firewall on the host (if any).
364
365 Needs elevated / admin / root privileges.
366
367 Returns success status, not logged.
368 """
369 fRc = False;
370
371 asArgs = [];
372 sOsType = sys.platform;
373
374 if sOsType == 'win32':
375 reporter.log('Disabling firewall on host (type: %s) ...' % (sOsType));
376
377 ## @todo For now we ASSUME that we don't run (and don't support even) on old(er)
378 # Windows hosts than Vista.
379 asArgs = self.getWinFirewallArgsDisable('vista');
380 if asArgs:
381 fRc = self.executeHst('Disabling host firewall', asArgs, fAsAdmin = True);
382 else:
383 reporter.log('Firewall not available on host, skipping');
384 fRc = True; # Not available, just skip.
385
386 return fRc;
387
388 def getLastRcFromTxs(self, oTxsSession):
389 """
390 Extracts the last exit code reported by TXS from a run before.
391 Assumes that nothing else has been run on the same TXS session in the meantime.
392 """
393 iRc = 0;
394 (_, sOpcode, abPayload) = oTxsSession.getLastReply();
395 if sOpcode.startswith('PROC NOK '): # Extract process rc
396 iRc = abPayload[0]; # ASSUMES 8-bit rc for now.
397 return iRc;
398
399 def startVkatOnGuest(self, oTestVm, oSession, oTxsSession):
400 """
401 Starts VKAT on the guest (running in background).
402 """
403 sPathTemp = self.getGuestTempDir(oTestVm);
404 sPathAudioOut = oTestVm.pathJoin(sPathTemp, 'vkat-guest-out');
405 sPathAudioTemp = oTestVm.pathJoin(sPathTemp, 'vkat-guest-temp');
406
407 reporter.log('Guest audio test temp path is \"%s\"' % (sPathAudioOut));
408 reporter.log('Guest audio test output path is \"%s\"' % (sPathAudioTemp));
409
410 fRc, sVkatExe = self.locateGstVkat(oSession, oTxsSession);
411 if fRc:
412 reporter.log('Using VKAT on guest at \"%s\"' % (sVkatExe));
413
414 asArgs = [ sVkatExe, 'test', '--mode', 'guest', '--probe-backends', \
415 '--tempdir', sPathAudioTemp, '--outdir', sPathAudioOut ];
416
417 for _ in range(1, reporter.getVerbosity()): # Verbosity always is initialized at 1.
418 asArgs.extend([ '-v' ]);
419
420 # Needed for NATed VMs.
421 asArgs.extend(['--tcp-connect-addr', '10.0.2.2' ]);
422
423 #
424 # Add own environment stuff.
425 #
426 asEnv = [];
427
428 # Enable more verbose logging for all groups. Disable later again?
429 asEnv.extend([ 'VKAT_RELEASE_LOG=all.e.l.l2.l3.f+audio_test.e.l.l2.l3.f' ]);
430
431 # Write the log file to some deterministic place so TxS can retrieve it later.
432 sVkatLogFile = 'VKAT_RELEASE_LOG_DEST=file=' + self.getGstVkatLogFilePath(oTestVm);
433 asEnv.extend([ sVkatLogFile ]);
434
435 #
436 # Execute asynchronously on the guest.
437 #
438 fRc = oTxsSession.asyncExec(sVkatExe, asArgs, asEnv, cMsTimeout = 15 * 60 * 1000);
439 if fRc:
440 self.addTask(oTxsSession);
441
442 if not fRc:
443 reporter.error('VKAT on guest returned exit code error %d' % (self.getLastRcFromTxs(oTxsSession)));
444 else:
445 reporter.error('VKAT on guest not found');
446
447 return fRc;
448
449 def runTests(self, oTestVm, oSession, oTxsSession, sDesc, asTests):
450 """
451 Runs one or more tests using VKAT on the host, which in turn will
452 communicate with VKAT running on the guest and the Validation Kit
453 audio driver ATS (Audio Testing Service).
454 """
455 _ = oSession, oTxsSession;
456 sTag = uuid.uuid4();
457
458 sPathTemp = self.sScratchPath;
459 sPathAudioOut = oTestVm.pathJoin(sPathTemp, 'vkat-host-out-%s' % (sTag));
460 sPathAudioTemp = oTestVm.pathJoin(sPathTemp, 'vkat-host-temp-%s' % (sTag));
461
462 reporter.log('Host audio test temp path is \"%s\"' % (sPathAudioOut));
463 reporter.log('Host audio test output path is \"%s\"' % (sPathAudioTemp));
464 reporter.log('Host audio test tag is \"%s\"' % (sTag));
465
466 reporter.testStart(sDesc);
467
468 sVkatExe = self.getBinTool('vkat');
469
470 reporter.log('Using VKAT on host at: \"%s\"' % (sVkatExe));
471
472 # Enable more verbose logging for all groups. Disable later again?
473 asEnv = [ 'VKAT_RELEASE_LOG=all.e.l.l2.l3.f+audio_test.e.l.l2.l3.f' ];
474
475 # Build the base command line, exclude all tests by default.
476 asArgs = [ sVkatExe, 'test', '--mode', 'host', '--probe-backends', \
477 '--tempdir', sPathAudioTemp, '--outdir', sPathAudioOut, '-a' ];
478
479 for _ in range(1, reporter.getVerbosity()): # Verbosity always is initialized at 1.
480 asArgs.extend([ '-v' ]);
481
482 # ... and extend it with wanted tests.
483 asArgs.extend(asTests);
484
485 #
486 # Let VKAT on the host run synchronously.
487 #
488 fRc = self.executeHst("VKAT Host", asArgs, asEnv);
489
490 reporter.testDone();
491
492 return fRc;
493
494 def doTest(self, oTestVm, oSession, oTxsSession):
495 """
496 Executes the specified audio tests.
497 """
498
499 # Disable any OS-specific firewalls preventing VKAT / ATS to run.
500 fRc = self.disableHstFirewall();
501 fRc = self.disableGstFirewall(oTestVm, oTxsSession) and fRc;
502
503 if not fRc:
504 return False;
505
506 # First try to kill any old VKAT / VBoxAudioTest processes lurking around on the host.
507 # Might happen because of former (aborted) runs.
508 self.killHstVkat();
509
510 reporter.log("Active tests: %s" % (self.asTests,));
511
512 fRc = self.startVkatOnGuest(oTestVm, oSession, oTxsSession);
513 if fRc:
514 #
515 # Execute the tests using VKAT on the guest side (in guest mode).
516 #
517 if "guest_tone_playback" in self.asTests:
518 fRc = self.runTests(oTestVm, oSession, oTxsSession, 'Guest audio playback', asTests = [ '-i0' ]);
519 if "guest_tone_recording" in self.asTests:
520 fRc = fRc and self.runTests(oTestVm, oSession, oTxsSession, 'Guest audio recording', asTests = [ '-i1' ]);
521
522 # Cancel guest VKAT execution task summoned by startVkatOnGuest().
523 oTxsSession.cancelTask();
524
525 #
526 # Retrieve log files for diagnosis.
527 #
528 self.txsDownloadFiles(oSession, oTxsSession,
529 [ ( self.getGstVkatLogFilePath(oTestVm),
530 'vkat-guest-%s.log' % (oTestVm.sVmName,),),
531 ],
532 fIgnoreErrors = True);
533 return fRc;
534
535 def testOneVmConfig(self, oVM, oTestVm):
536 """
537 Runs tests using one specific VM config.
538 """
539
540 self.logVmInfo(oVM);
541
542 reporter.testStart("Audio Testing");
543
544 fSkip = False;
545
546 if oTestVm.isWindows() \
547 and oTestVm.sKind in ('WindowsNT4', 'Windows2000'): # Too old for DirectSound and WASAPI backends.
548 reporter.log('Audio testing skipped, not implemented/available for that OS yet.');
549 fSkip = True;
550
551 if not fSkip \
552 and self.fpApiVer < 7.0:
553 reporter.log('Audio testing for non-trunk builds skipped.');
554 fSkip = True;
555
556 sVkatExe = self.getBinTool('vkat');
557 asArgs = [ sVkatExe, 'enum', '--probe-backends' ];
558 fRc = self.executeHst("VKAT Host Audio Probing", asArgs);
559 if not fSkip \
560 and not fRc:
561 reporter.log('Audio not available on host, skipping audio tests.');
562 fSkip = True;
563
564 if fSkip:
565 reporter.testDone(fSkipped = True);
566 return True;
567
568 # Reconfigure the VM.
569 oSession = self.openSession(oVM);
570 if oSession is not None:
571 # Set extra data.
572 for sExtraData in self.asOptExtraData:
573 sKey, sValue = sExtraData.split(':');
574 reporter.log('Set extradata: %s => %s' % (sKey, sValue));
575 fRc = oSession.setExtraData(sKey, sValue) and fRc;
576
577 # Make sure that the VM's audio adapter is configured the way we need it to.
578 if self.fpApiVer >= 4.0:
579 oOsType = oSession.getOsType();
580 ## @ŧdoo Make this configurable via driver opts (to use as a variant)?
581 oSession.setupAudio(oOsType.recommendedAudioController,
582 fEnable = True, fEnableIn = True, fEnableOut = True);
583
584 # Save the settings.
585 fRc = fRc and oSession.saveSettings();
586 fRc = oSession.close() and fRc;
587
588 reporter.testStart('Waiting for TXS');
589 oSession, oTxsSession = self.startVmAndConnectToTxsViaTcp(oTestVm.sVmName,
590 fCdWait = True,
591 cMsTimeout = 3 * 60 * 1000,
592 sFileCdWait = '${OS/ARCH}/vkat${EXESUFF}');
593 reporter.testDone();
594
595 if oSession is not None:
596 self.addTask(oTxsSession);
597
598 fRc = self.doTest(oTestVm, oSession, oTxsSession);
599
600 # Cleanup.
601 self.removeTask(oTxsSession);
602 self.terminateVmBySession(oSession);
603
604 reporter.testDone();
605 return fRc;
606
607 def onExit(self, iRc):
608 """
609 Exit handler for this test driver.
610 """
611 return vbox.TestDriver.onExit(self, iRc);
612
613if __name__ == '__main__':
614 sys.exit(tdAudioTest().main(sys.argv))
Note: See TracBrowser for help on using the repository browser.

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