1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.aludratest.service.file.impl;
17
18 import java.io.BufferedReader;
19 import java.io.ByteArrayInputStream;
20 import java.io.ByteArrayOutputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.InputStreamReader;
24 import java.io.OutputStream;
25 import java.io.OutputStreamWriter;
26 import java.io.PrintWriter;
27 import java.io.Reader;
28 import java.io.StringReader;
29 import java.io.StringWriter;
30 import java.io.UnsupportedEncodingException;
31 import java.io.Writer;
32 import java.util.ArrayList;
33 import java.util.List;
34
35 import org.aludratest.exception.AutomationException;
36 import org.aludratest.exception.FunctionalFailure;
37 import org.aludratest.exception.TechnicalException;
38 import org.aludratest.service.SystemConnector;
39 import org.aludratest.service.file.FileCondition;
40 import org.aludratest.service.file.FileFilter;
41 import org.aludratest.service.file.FileInfo;
42 import org.aludratest.service.file.FileInteraction;
43 import org.aludratest.service.file.FileService;
44 import org.aludratest.service.file.FileVerification;
45 import org.aludratest.service.file.filter.RegexFilePathFilter;
46 import org.aludratest.service.file.util.FileUtil;
47 import org.aludratest.testcase.event.attachment.Attachment;
48 import org.aludratest.util.poll.PollService;
49 import org.aludratest.util.poll.PolledTask;
50 import org.apache.commons.vfs2.AllFileSelector;
51 import org.apache.commons.vfs2.FileObject;
52 import org.apache.commons.vfs2.FileSelector;
53 import org.apache.commons.vfs2.FileSystemException;
54 import org.apache.commons.vfs2.FileType;
55 import org.databene.commons.IOUtil;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59
60
61
62
63
64 public class FileActionImpl implements FileInteraction, FileVerification, FileCondition {
65
66 private static final Logger LOGGER = LoggerFactory.getLogger(FileActionImpl.class);
67
68
69 private FileServiceConfiguration configuration;
70
71
72 private PollService pollService;
73
74
75
76 public FileActionImpl(FileServiceConfiguration configuration) {
77 this.configuration = configuration;
78 this.pollService = new PollService(configuration.getTimeout(), configuration.getPollingDelay());
79 getChildren(getRootFolder());
80 }
81
82 @Override
83 public void setSystemConnector(SystemConnector systemConnector) {
84
85 }
86
87
88 @Override
89 public String getRootFolder() {
90 return "/";
91 }
92
93
94 @Override
95 public final List<String> getChildren(String filePath) {
96 FileUtil.verifyFilePath(filePath);
97 return getChildren(filePath, (FileFilter) null);
98 }
99
100
101 @Override
102 public List<String> getChildren(String filePath, String filterRegex) {
103 FileUtil.verifyFilePath(filePath);
104 return getChildren(filePath, new RegexFilePathFilter(filterRegex));
105 }
106
107
108 @Override
109 public List<String> getChildren(String filePath, FileFilter filter) {
110 FileUtil.verifyFilePath(filePath);
111 try {
112 FileObject parent = configuration.getFileObject(filePath);
113 parent.refresh();
114 FileObject[] candidates = parent.getChildren();
115 List<String> filePaths = new ArrayList<String>();
116 if (candidates != null) {
117 for (FileObject candidate : candidates) {
118 if (filter == null || filter.accept(new FileInfo(candidate))) {
119 filePaths.add(pathFromRoot(candidate));
120 }
121 }
122 }
123 if (filePaths.size() > 0) {
124 LOGGER.debug("Found children: {}", filePaths);
125 } else {
126 LOGGER.debug("No children found for filter {}", filter);
127 }
128 return filePaths;
129 } catch (FileSystemException e) {
130 throw new TechnicalException("Error retrivieving child objects", e);
131 }
132 }
133
134
135 @Override
136 public void createDirectory(String filePath) {
137 assertWritingPermitted("createDirectory()");
138 FileUtil.verifyFilePath(filePath);
139 try {
140 getFileObject(filePath).createFolder();
141 LOGGER.debug("Created directory {}", filePath);
142 } catch (FileSystemException e) {
143 throw new TechnicalException("Directory creation failed", e);
144 }
145 }
146
147
148
149
150
151
152
153 @Override
154 public boolean move(String fromPath, String toPath, boolean overwrite) {
155 assertWritingPermitted("move()");
156 FileUtil.verifyFilePath(fromPath);
157 FileUtil.verifyFilePath(toPath);
158 FileObject target = getFileObject(toPath);
159 boolean existedBefore = checkWritable(target, overwrite);
160 try {
161 getOrCreateDirectory(target.getParent());
162 getFileObject(fromPath).moveTo(target);
163 LOGGER.debug("Moved {} to {}", fromPath, toPath);
164 return existedBefore;
165 } catch (FileSystemException e) {
166 throw new TechnicalException("Error moving file" + fromPath + " -> " + toPath, e);
167 }
168 }
169
170
171
172
173
174
175
176 @Override
177 public boolean copy(String fromPath, String toPath, boolean overwrite) {
178 assertWritingPermitted("copy()");
179 FileUtil.verifyFilePath(fromPath);
180 FileUtil.verifyFilePath(toPath);
181 FileObject target = getFileObject(toPath);
182 boolean existedBefore = checkWritable(target, overwrite);
183 try {
184 FileObject source = getFileObject(fromPath);
185 FileSelector sourceSelector = new FilePathSelector(source.getName().getPath());
186 target.copyFrom(source, sourceSelector);
187 LOGGER.debug("Copied {} to {}", fromPath, toPath);
188 return existedBefore;
189 } catch (FileSystemException e) {
190 throw new TechnicalException("Error copying file " + fromPath + " -> " + toPath, e);
191 }
192 }
193
194
195 @Override
196 public void delete(String filePath) {
197 assertWritingPermitted("delete()");
198 FileUtil.verifyFilePath(filePath);
199 try {
200 getFileObject(filePath).delete(new AllFileSelector());
201 LOGGER.debug("Deleted {}", filePath);
202 } catch (FileSystemException e) {
203 throw new TechnicalException("Error deleting file", e);
204 }
205 }
206
207
208
209
210
211
212
213 @Override
214 public boolean writeTextFile(String filePath, String content, boolean overwrite) {
215 assertWritingPermitted("writeTextFile()");
216 FileUtil.verifyFilePath(filePath);
217 return writeTextFile(filePath, new StringReader(content), overwrite);
218 }
219
220
221
222
223
224
225
226 @Override
227 public boolean writeTextFile(String filePath, Reader source, boolean overwrite) {
228 assertWritingPermitted("writeTextFile()");
229 FileUtil.verifyFilePath(filePath);
230 String encoding = configuration.getEncoding();
231 Writer writer = null;
232 BufferedReader reader = null;
233 try {
234 String linefeed = configuration.getLinefeed();
235 FileObject target = getFileObject(filePath);
236 boolean existedBefore = checkWritable(target, overwrite);
237 writer = new OutputStreamWriter(target.getContent().getOutputStream(), encoding);
238 reader = new BufferedReader(source);
239 boolean firstLine = true;
240 String line;
241 while ((line = reader.readLine()) != null) {
242 if (!firstLine) {
243 writer.write(linefeed);
244 }
245 writer.write(line);
246 firstLine = false;
247 }
248 LOGGER.debug("Wrote text file {}", filePath);
249 return existedBefore;
250 } catch (UnsupportedEncodingException e) {
251 throw new TechnicalException("Unsupported Encoding:" + encoding, e);
252 } catch (Exception e) {
253 throw new TechnicalException("Error writing text file", e);
254 } finally {
255 IOUtil.close(writer);
256 IOUtil.close(reader);
257 }
258 }
259
260
261
262
263
264
265
266 @Override
267 public boolean writeBinaryFile(String filePath, byte[] bytes, boolean overwrite) {
268 assertWritingPermitted("writeBinaryFile()");
269 ByteArrayInputStream in = new ByteArrayInputStream(bytes);
270 return writeBinaryFile(filePath, in, overwrite);
271 }
272
273
274
275
276
277
278
279 @Override
280 public boolean writeBinaryFile(String filePath, InputStream source, boolean overwrite) {
281 assertWritingPermitted("writeBinaryFile()");
282 FileUtil.verifyFilePath(filePath);
283 OutputStream out = null;
284 try {
285 FileObject target = getFileObject(filePath);
286 boolean existedBefore = checkWritable(target, overwrite);
287 out = target.getContent().getOutputStream();
288 IOUtil.transfer(source, out);
289 LOGGER.debug("Wrote binary file {}", filePath);
290 return existedBefore;
291 } catch (Exception e) {
292 throw new TechnicalException("Error writing text file", e);
293 } finally {
294 IOUtil.close(out);
295 }
296 }
297
298
299 @Override
300 public String readTextFile(String filePath) {
301 FileUtil.verifyFilePath(filePath);
302 BufferedReader reader = null;
303 try {
304 StringWriter writer = new StringWriter();
305 PrintWriter printer = new PrintWriter(writer);
306 reader = getReaderForTextFile(filePath);
307 boolean firstLine = true;
308 String line;
309 while ((line = reader.readLine()) != null) {
310 if (!firstLine) {
311 printer.println();
312 }
313 printer.write(line);
314 firstLine = false;
315 }
316 LOGGER.debug("Text file read: {}", filePath);
317 return writer.toString();
318 } catch (IOException e) {
319 throw new TechnicalException("Error reading text file", e);
320 } finally {
321 IOUtil.close(reader);
322 }
323 }
324
325
326 @Override
327 public BufferedReader getReaderForTextFile(String filePath) {
328 FileUtil.verifyFilePath(filePath);
329 String encoding = configuration.getEncoding();
330 try {
331 LOGGER.debug("Providing reader for text file: {}", filePath);
332 return new BufferedReader(new InputStreamReader(getInputStreamForFile(filePath), encoding));
333 } catch (UnsupportedEncodingException e) {
334 throw new TechnicalException("Unsupported Encoding:" + encoding, e);
335 }
336 }
337
338
339 @Override
340 public byte[] readBinaryFile(String filePath) {
341 FileUtil.verifyFilePath(filePath);
342 InputStream in = null;
343 try {
344 in = getInputStreamForFile(filePath);
345 ByteArrayOutputStream out = new ByteArrayOutputStream();
346 IOUtil.transfer(in, out);
347 LOGGER.debug("Binary file read: {}", filePath);
348 return out.toByteArray();
349 } catch (IOException e) {
350 throw new TechnicalException("Error reading binary file", e);
351 } finally {
352 IOUtil.close(in);
353 }
354 }
355
356
357 @Override
358 public InputStream getInputStreamForFile(String filePath) {
359 FileUtil.verifyFilePath(filePath);
360 FileObject file = getFileObject(filePath);
361 try {
362 LOGGER.debug("Providing InputStream for binary file: {}", filePath);
363 return file.getContent().getInputStream();
364 } catch (FileSystemException e) {
365 throw new TechnicalException("Error opening InputStream", e);
366 }
367 }
368
369
370
371
372
373 @Override
374 public void waitUntilExists(String elementType, String filePath) {
375 FileUtil.verifyFilePath(filePath);
376 pollService.poll(new WaitForFileTask(filePath, true));
377 }
378
379
380
381
382
383 @Override
384 public void waitUntilNotExists(String filePath) {
385 FileUtil.verifyFilePath(filePath);
386 pollService.poll(new WaitForFileTask(filePath, false));
387 }
388
389
390
391
392
393 @Override
394 public String waitForFirstMatch(String parentPath, FileFilter filter) {
395 FileUtil.verifyFilePath(parentPath);
396 if (!exists(parentPath)) {
397 throw new AutomationException("Directory not found: " + parentPath);
398 }
399 if (!isDirectory(parentPath)) {
400 throw new AutomationException("Not a directory: " + parentPath);
401 }
402 if (filter == null) {
403 throw new AutomationException("Filter is null");
404 }
405 return pollService.poll(new WaitForFirstMatchTask(parentPath, filter));
406 }
407
408
409
410 @Override
411 public void assertPresence(String filePath) {
412 FileUtil.verifyFilePath(filePath);
413 if (!exists(filePath)) {
414 throw new AutomationException("Expected file not present: " + filePath);
415 } else {
416 LOGGER.debug("File exists as expected: {}", filePath);
417 }
418
419 }
420
421
422
423 @Override
424 public void assertAbsence(String filePath) {
425 FileUtil.verifyFilePath(filePath);
426 if (exists(filePath)) {
427 throw new AutomationException("File expected to be absent: " + filePath);
428 } else {
429 LOGGER.debug("File is absent as expected: {}", filePath);
430 }
431 }
432
433
434 @Override
435 public boolean exists(String filePath) {
436 FileUtil.verifyFilePath(filePath);
437 try {
438 FileObject file = getFileObject(filePath);
439 file.refresh();
440 boolean result = file.exists();
441 LOGGER.debug("File '{}' {}", filePath, (result ? "exists" : "does not exist"));
442 return result;
443 } catch (FileSystemException e) {
444 throw new TechnicalException("Error checking file presence", e);
445 }
446 }
447
448 @Override
449 public void assertFile(String filePath) {
450 FileUtil.verifyFilePath(filePath);
451 assertPresence(filePath);
452 if (isDirectory(filePath)) {
453 throw new FunctionalFailure("Not a file: " + filePath);
454 } else {
455 LOGGER.debug("File is not a directory: {}", filePath);
456 }
457 }
458
459 @Override
460 public void assertDirectory(String filePath) {
461 FileUtil.verifyFilePath(filePath);
462 assertPresence(filePath);
463 if (!isDirectory(filePath)) {
464 throw new FunctionalFailure("Not a directory: " + filePath);
465 } else {
466 LOGGER.debug("File is not directory: {}", filePath);
467 }
468 }
469
470
471 @Override
472 public boolean isDirectory(String filePath) {
473 FileUtil.verifyFilePath(filePath);
474 try {
475 boolean result = getFileObject(filePath).getType() == FileType.FOLDER;
476 LOGGER.debug("{} is {}", filePath, (result ? "a folder" : "not a folder"));
477 return result;
478 } catch (FileSystemException e) {
479 throw new TechnicalException("Error accessing file or folder", e);
480 }
481 }
482
483 @Override
484 public List<Attachment> createAttachments(Object object, String label) {
485 throw new TechnicalException("Not supported");
486 }
487
488 @Override
489 public List<Attachment> createDebugAttachments() {
490 return null;
491 }
492
493
494
495 private FileObject getFileObject(String pathFromRoot) {
496 return configuration.getFileObject(pathFromRoot);
497 }
498
499 private String pathFromRoot(FileObject file) {
500 return configuration.pathFromRoot(file);
501 }
502
503 private boolean checkWritable(FileObject file, boolean overwrite) {
504 try {
505 if (file.exists()) {
506 if (overwrite) {
507 file.delete();
508 } else {
509 throw new FunctionalFailure("File expected to be absent: " + pathFromRoot(file));
510 }
511 return true;
512 } else {
513 return false;
514 }
515 } catch (FileSystemException e) {
516 throw new TechnicalException("Error checking file", e);
517 }
518 }
519
520 private void getOrCreateDirectory(FileObject directory) {
521 FileObject root = configuration.getRootFolder();
522 if (!root.equals(directory)) {
523 try {
524 getOrCreateDirectory(directory.getParent());
525 directory.createFolder();
526 } catch (FileSystemException e) {
527 throw new TechnicalException("Error creating directory", e);
528 }
529 }
530 }
531
532 private void assertWritingPermitted(String operation) {
533 if (!configuration.isWritingPermitted()) {
534 throw new AutomationException("Invoked " + operation + " on a write protected file system");
535 }
536 }
537
538 private class WaitForFileTask implements PolledTask<String> {
539
540 private String filePath;
541 private boolean awaitExistence;
542
543 public WaitForFileTask(String filePath, boolean awaitExistence) {
544 this.filePath = filePath;
545 this.awaitExistence = awaitExistence;
546 }
547
548 @Override
549 public String run() {
550 FileObject file = getFileObject(filePath);
551 try {
552 if (!awaitExistence) {
553
554
555 FileObject parent = file.getParent();
556 parent.getType();
557 parent.refresh();
558
559
560 }
561 file.refresh();
562 if (file.exists()) {
563 LOGGER.debug("File found: {}", filePath);
564 return (awaitExistence ? filePath : null);
565 } else {
566 LOGGER.debug("File not found: {}", filePath);
567 return (awaitExistence ? null : filePath);
568 }
569 } catch (FileSystemException e) {
570 throw new TechnicalException("Error checking presence of file ", e);
571 }
572 }
573
574 @Override
575 public String timedOut() {
576 String expectedState = (awaitExistence ? "found" : "removed");
577 throw new FunctionalFailure("File not " + expectedState + " within timeout: " + filePath);
578 }
579
580 @Override
581 public String toString() {
582 return getClass().getSimpleName() + "(" + filePath + ")";
583 }
584
585 }
586
587
588
589
590
591 public class WaitForFirstMatchTask implements PolledTask<String> {
592
593 private String parentPath;
594 private FileFilter filter;
595
596
597
598
599 public WaitForFirstMatchTask(String parentPath, FileFilter filter) {
600 this.parentPath = parentPath;
601 this.filter = filter;
602 }
603
604 @Override
605 public String run() {
606 List<String> children = getChildren(parentPath, filter);
607 if (children.size() > 0) {
608 String result = children.get(0);
609 LOGGER.debug("File found: {}", result);
610 return result;
611 } else {
612 LOGGER.debug("No match found for {}", filter);
613 return null;
614 }
615 }
616
617 @Override
618 public String timedOut() {
619 throw new FunctionalFailure("No match found for filter " + filter);
620 }
621
622 @Override
623 public String toString() {
624 return getClass().getSimpleName() + "(" + filter.toString() + ")";
625 }
626
627 }
628
629 }