├── .gitignore
├── .travis.yml
├── LICENSE.txt
├── README.md
├── Vagrantfile
├── catlogs.sh
├── glusterfs-java-filesystem-example
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── peircean
│ │ │ └── glusterfs
│ │ │ └── example
│ │ │ └── Example.java
│ └── resources
│ │ └── example.properties
│ └── test
│ └── java
│ └── ExampleTest.java
├── glusterfs-java-filesystem
├── NOTICE.txt
├── pom.xml
├── sonar.txt
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── peircean
│ │ │ └── glusterfs
│ │ │ ├── GlusterDirectoryIterator.java
│ │ │ ├── GlusterDirectoryStream.java
│ │ │ ├── GlusterFileAttributes.java
│ │ │ ├── GlusterFileChannel.java
│ │ │ ├── GlusterFileStore.java
│ │ │ ├── GlusterFileSystem.java
│ │ │ ├── GlusterFileSystemProvider.java
│ │ │ ├── GlusterPath.java
│ │ │ ├── GlusterPathMatcher.java
│ │ │ ├── GlusterWatchEvent.java
│ │ │ ├── GlusterWatchKey.java
│ │ │ ├── GlusterWatchService.java
│ │ │ └── borrowed
│ │ │ └── GlobPattern.java
│ └── resources
│ │ └── META-INF
│ │ └── services
│ │ └── java.nio.file.spi.FileSystemProvider
│ └── test
│ └── java
│ └── com
│ └── peircean
│ └── glusterfs
│ ├── GlusterDirectoryIteratorTest.java
│ ├── GlusterDirectoryStreamTest.java
│ ├── GlusterFileAttributesTest.java
│ ├── GlusterFileChannelTest.java
│ ├── GlusterFileStoreTest.java
│ ├── GlusterFileSystemProviderTest.java
│ ├── GlusterFileSystemTest.java
│ ├── GlusterPathMatcherTest.java
│ ├── GlusterPathPowerMockTest.java
│ ├── GlusterPathTest.java
│ ├── GlusterWatchKeyTest.java
│ └── GlusterWatchServiceTest.java
├── pom.xml
└── vagrant-provisioner.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | *.swp
3 | .idea
4 | .idea/*
5 | *.iml
6 | *.ipr
7 | *.iws
8 | target
9 | .DS_Store
10 | .project
11 | .classpath
12 | .settings
13 | eclipse-classes
14 | hs_err_pid*.log
15 | .vagrant
16 | .clover
17 | dependency-reduced-pom.xml
18 | release.properties
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk:
3 | - openjdk7
4 | before_install:
5 | - sudo add-apt-repository ppa:gluster/glusterfs-3.4 -y
6 | - sudo apt-get update -qq -y
7 | - sudo apt-get install glusterfs-common -y
8 | after_script: bash catlogs.sh
9 | notifications:
10 | email: false
11 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 Louis Zuckerman All rights reserved.
2 |
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are
5 | met:
6 |
7 | * Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above
10 | copyright notice, this list of conditions and the following disclaimer
11 | in the documentation and/or other materials provided with the
12 | distribution.
13 | * Neither the names of the authors nor the names of
14 | contributors may be used to endorse or promote products derived from
15 | this software without specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # glusterfs-java-filesystem
2 |
3 | This project aims to be a complete implementation of a Java7/NIO.2 File System Provider backed by
4 | [GlusterFS](http://www.gluster.org/) via [libgfapi-jni](https://github.com/semiosis/libgfapi-jni)
5 |
6 | [](https://travis-ci.org/semiosis/glusterfs-java-filesystem)
7 |
8 | [](http://sonar.peircean.com/dashboard/index/com.peircean.glusterfs:glusterfs-java-filesystem)
9 |
10 | [Test Coverage & Code Quality](http://sonar.peircean.com/dashboard/index/com.peircean.glusterfs:glusterfs-java-filesystem)
11 |
12 | Please let me know if you use this project, even if you're just checking it out, I'd like to hear from you.
13 |
14 | I prefer to be contacted on IRC, Twitter, or a Github issue. You can find me, semiosis, in #gluster on Freenode IRC. My twitter handle is @pragmaticism.
15 |
16 | Thanks!
17 |
18 | # Use
19 |
20 | ## Adding to your maven project
21 |
22 |
23 |
24 | com.peircean.glusterfs
25 | glusterfs-java-filesystem
26 | 1.0.4
27 |
28 |
29 |
30 | ## Adding to your non-maven project
31 |
32 | The maven shade plugin can build a unified (shaded) JAR suitable for dropping in to the classpath of any JVM application.
33 |
34 | You can build a "shaded" JAR by cloning the project and running the following command in the glusterfs-java-filesystem subdirectory:
35 |
36 | cd glusterfs-java-filesystem
37 | mvn package shade:shade
38 |
39 | Maven will report the path of this shaded JAR. You can run `export CLASSPATH=` in a terminal before running your other application.
40 |
41 | Contact me (on IRC, Twitter, or in a Github issue) if you need help obtaining a JAR, if you can't, or don't want to, build it with maven yourself.
42 |
43 | ## Access GlusterFS volumes with the NIO.2 API
44 |
45 | Once this library is in your classpath all you need to do in your code is access a GlusterFS URI, for example
46 |
47 | gluster://server:volume/path
48 |
49 | ## Example usage
50 |
51 | A Vagrantfile in the root of this repository sets up a VM with a volume called *foo* at IP address *172.31.31.31* on a
52 | private network.
53 |
54 | The [Example.java](glusterfs-java-filesystem-example/src/main/java/com/peircean/glusterfs/example/Example.java) file in
55 | the glusterfs-java-filesystem-example project provides a demonstration of the capabilities of this project from a high
56 | level consumer's point of view, it connects to the volume on the vagrant VM.
57 |
58 | To run:
59 |
60 | cd glusterfs-java-filesystem-example
61 | vagrant up
62 | mvn exec:exec
63 |
64 | # Roadmap
65 |
66 | ### TODO:
67 |
68 | - Replace Example program with formal integration test suite
69 | - Align project versions with glusterfs (this project & libgfapi-jni)
70 | - Update watch service to use [libgfchangelog](https://github.com/gluster/glusterfs/blob/master/xlators/features/changelog/lib/examples/c/get-changes.c) (instead of polling)
71 | - Finish attribute support
72 | Owner/group names & ability to change
73 | More ways to set permissions
74 | - Finish integration testing for advanced synchronous file IO (reading/writing portion of file)
75 | - Asychronous file I/O
76 | - Better error reporting & handling (utilize UtilJNI.strerror() as part of IOException throws)
77 | - Finish readSymbolicLink unit tests
78 | - Publish test coverage report to Coveralls.io
79 | [Blocked](https://github.com/trautonen/coveralls-maven-plugin/issues/36) due to use of Atlassian Clover
80 | - Create hard links
81 |
82 | ### Completed:
83 |
84 | - Connect to a GlusterFS volume using the NIO.2 API
85 | - Basic synchronous file I/O
86 | Read the contents of a file all at once
87 | Write a chunk of bytes to a file all at once
88 | - File attributes
89 | See owner/group id, size, permissions, and last modified timestamp on files and directories
90 | Set permissions
91 | - Filesystem/volume stats
92 | See the total, free, and usable bytes in a volume
93 | - Directory listing (with filtering)
94 | - Move/rename files
95 | - Watch files for changes
96 | Complete except for GlusterWatchKeyTest, in progress
97 | - Create & Read symlinks (read tests incomplete)
98 | - Publish test coverage & code quality reports to [SonarQube](http://sonar.peircean.com/dashboard/index/com.peircean.glusterfs:glusterfs-java-filesystem)
99 | - Delete files
100 | - Copy files
101 | - Advanced synchronous file IO
102 |
103 | # Contributing/Development
104 |
105 | I'd appreciate your help with this project. If you have any feedback at all please get in touch. I'm interested in everything from gripes to pull requests.
106 |
107 | # Project License
108 |
109 | Until further notice (made here and in LICENSE.txt) this project is licensed under the terms of the
110 | 3-clause BSD license, as written in LICENSE.txt.
111 |
112 | The licensing is likely to change in the near future as the project matures.
113 |
114 | # Acknowledgements
115 |
116 | - May G. & Ian H. for their hard work & dedication to improving this project.
117 | - Atlassian for providing a free license for their most excellent Java code quality analyzer, [Clover](https://www.atlassian.com/software/clover/overview).
118 | - All the open source projects we depend on: [GlusterFS](http://gluster.org/), [HawtJNI](https://github.com/fusesource/hawtjni), [Lombok](http://projectlombok.org/), [JUnit](http://junit.org/), [Mockito](https://code.google.com/p/mockito/), [PowerMock](https://code.google.com/p/powermock/), [TestNG](http://testng.org/doc/index.html), [sonarqube](http://www.sonarqube.org/), [Hadoop](http://hadoop.apache.org/) (whose Glob to Regex converter we borrowed), [Maven](http://maven.apache.org/) and all the Maven plugins, and of course [Java](https://www.java.com/).
119 |
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | # Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
5 | VAGRANTFILE_API_VERSION = "2"
6 |
7 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
8 | # All Vagrant configuration is done here. The most common configuration
9 | # options are documented and commented below. For a complete reference,
10 | # please see the online documentation at vagrantup.com.
11 |
12 | # Every Vagrant virtual environment requires a box to build off of.
13 | config.vm.box = "xenial64"
14 |
15 | # The url from where the 'config.vm.box' box will be fetched if it
16 | # doesn't already exist on the user's system.
17 | config.vm.box_url = "https://cloud-images.ubuntu.com/xenial/current/xenial-server-cloudimg-amd64-vagrant.box"
18 |
19 | # Create a forwarded port mapping which allows access to a specific port
20 | # within the machine from a port on the host machine. In the example below,
21 | # accessing "localhost:8080" will access port 80 on the guest machine.
22 | # config.vm.network :forwarded_port, guest: 80, host: 8080
23 |
24 | # Create a private network, which allows host-only access to the machine
25 | # using a specific IP.
26 | private_ip = "172.31.31.31"
27 |
28 | config.vm.network :private_network, ip: private_ip
29 |
30 | config.vm.provision "shell" do |s|
31 | s.path = "vagrant-provisioner.sh"
32 | s.args = [private_ip]
33 | end
34 |
35 | # Create a public network, which generally matched to bridged network.
36 | # Bridged networks make the machine appear as another physical device on
37 | # your network.
38 | # config.vm.network :public_network
39 |
40 | # If true, then any SSH connections made will enable agent forwarding.
41 | # Default value: false
42 | # config.ssh.forward_agent = true
43 |
44 | # Share an additional folder to the guest VM. The first argument is
45 | # the path on the host to the actual folder. The second argument is
46 | # the path on the guest to mount the folder. And the optional third
47 | # argument is a set of non-required options.
48 | # config.vm.synced_folder "../data", "/vagrant_data"
49 |
50 | # Provider-specific configuration so you can fine-tune various
51 | # backing providers for Vagrant. These expose provider-specific options.
52 | # Example for VirtualBox:
53 | #
54 | # config.vm.provider :virtualbox do |vb|
55 | # # Don't boot with headless mode
56 | # vb.gui = true
57 | #
58 | # # Use VBoxManage to customize the VM. For example to change memory:
59 | # vb.customize ["modifyvm", :id, "--memory", "1024"]
60 | # end
61 | #
62 | # View the documentation for the provider you're using for more
63 | # information on available options.
64 |
65 | # Enable provisioning with Puppet stand alone. Puppet manifests
66 | # are contained in a directory path relative to this Vagrantfile.
67 | # You will need to create the manifests directory and a manifest in
68 | # the file base.pp in the manifests_path directory.
69 | #
70 | # An example Puppet manifest to provision the message of the day:
71 | #
72 | # # group { "puppet":
73 | # # ensure => "present",
74 | # # }
75 | # #
76 | # # File { owner => 0, group => 0, mode => 0644 }
77 | # #
78 | # # file { '/etc/motd':
79 | # # content => "Welcome to your Vagrant-built virtual machine!
80 | # # Managed by Puppet.\n"
81 | # # }
82 | #
83 | # config.vm.provision :puppet do |puppet|
84 | # puppet.manifests_path = "manifests"
85 | # puppet.manifest_file = "site.pp"
86 | # end
87 |
88 | # Enable provisioning with chef solo, specifying a cookbooks path, roles
89 | # path, and data_bags path (all relative to this Vagrantfile), and adding
90 | # some recipes and/or roles.
91 | #
92 | # config.vm.provision :chef_solo do |chef|
93 | # chef.cookbooks_path = "../my-recipes/cookbooks"
94 | # chef.roles_path = "../my-recipes/roles"
95 | # chef.data_bags_path = "../my-recipes/data_bags"
96 | # chef.add_recipe "mysql"
97 | # chef.add_role "web"
98 | #
99 | # # You may also specify custom JSON attributes:
100 | # chef.json = { :mysql_password => "foo" }
101 | # end
102 |
103 | # Enable provisioning with chef server, specifying the chef server URL,
104 | # and the path to the validation key (relative to this Vagrantfile).
105 | #
106 | # The Opscode Platform uses HTTPS. Substitute your organization for
107 | # ORGNAME in the URL and validation key.
108 | #
109 | # If you have your own Chef Server, use the appropriate URL, which may be
110 | # HTTP instead of HTTPS depending on your configuration. Also change the
111 | # validation key to validation.pem.
112 | #
113 | # config.vm.provision :chef_client do |chef|
114 | # chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
115 | # chef.validation_key_path = "ORGNAME-validator.pem"
116 | # end
117 | #
118 | # If you're using the Opscode platform, your validator client is
119 | # ORGNAME-validator, replacing ORGNAME with your organization name.
120 | #
121 | # If you have your own Chef Server, the default validation client name is
122 | # chef-validator, unless you changed the configuration.
123 | #
124 | # chef.validation_client_name = "ORGNAME-validator"
125 | end
126 |
--------------------------------------------------------------------------------
/catlogs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | for i in `find . -path '**/surefire-reports/**'`; do
3 | echo
4 | echo
5 | echo $i
6 | cat $i
7 | done
--------------------------------------------------------------------------------
/glusterfs-java-filesystem-example/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | glusterfs-java-filesystem-project
5 | com.peircean.glusterfs
6 | 1.0.5-SNAPSHOT
7 |
8 | 4.0.0
9 |
10 | com.peircean.glusterfs
11 | glusterfs-java-filesystem-example
12 | 1.0.5-SNAPSHOT
13 |
14 |
15 | 172.31.31.31
16 | foo
17 |
18 |
19 |
20 |
21 |
22 | ${project.basedir}/src/main/resources
23 | true
24 |
25 | **/*
26 |
27 |
28 |
29 |
30 |
31 | org.codehaus.mojo
32 | exec-maven-plugin
33 | 1.2.1
34 |
35 |
36 |
37 | exec
38 |
39 |
40 |
41 |
42 | java
43 |
44 | -classpath
45 |
47 |
48 | com.peircean.glusterfs.example.Example
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | com.peircean.glusterfs
58 | glusterfs-java-filesystem
59 | 1.0.5-SNAPSHOT
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem-example/src/main/java/com/peircean/glusterfs/example/Example.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs.example;
2 |
3 | import com.peircean.glusterfs.GlusterFileSystem;
4 | import com.peircean.glusterfs.GlusterPath;
5 |
6 | import java.io.IOException;
7 | import java.net.URI;
8 | import java.net.URISyntaxException;
9 | import java.nio.file.*;
10 | import java.nio.file.attribute.FileAttribute;
11 | import java.nio.file.attribute.PosixFilePermission;
12 | import java.nio.file.attribute.PosixFilePermissions;
13 | import java.nio.file.spi.FileSystemProvider;
14 | import java.util.List;
15 | import java.util.Properties;
16 | import java.util.Set;
17 | import java.util.concurrent.TimeUnit;
18 |
19 | /**
20 | * @author Louis Zuckerman
21 | */
22 | public class Example {
23 | public static FileSystemProvider getProvider(String scheme) {
24 | for (FileSystemProvider fsp : FileSystemProvider.installedProviders()) {
25 | if (fsp.getScheme().equals(scheme)) {
26 | return fsp;
27 | }
28 | }
29 | throw new IllegalArgumentException("No provider found for scheme: " + scheme);
30 | }
31 |
32 | public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException {
33 | Properties properties = new Properties();
34 | properties.load(Example.class.getClassLoader().getResourceAsStream("example.properties"));
35 |
36 | String vagrantBox = properties.getProperty("glusterfs.server");
37 | String volname = properties.getProperty("glusterfs.volume");
38 |
39 | System.out.println(getProvider("gluster").toString());
40 |
41 | String mountUri = "gluster://" + vagrantBox + ":" + volname + "/";
42 | String testUri = "gluster://" + vagrantBox + ":" + volname + "/baz";
43 | Path mountPath = Paths.get(new URI(mountUri));
44 |
45 | FileSystem fileSystem = FileSystems.newFileSystem(new URI(mountUri), null);
46 | FileStore store = fileSystem.getFileStores().iterator().next();
47 | System.out.println("TOTAL SPACE: " + store.getTotalSpace());
48 | System.out.println("USABLE SPACE: " + store.getUsableSpace());
49 | System.out.println("UNALLOCATED SPACE: " + store.getUnallocatedSpace());
50 | System.out.println(fileSystem.toString());
51 |
52 | String hidden = "/foo/.bar";
53 | boolean isHidden = fileSystem.provider().isHidden(new GlusterPath(((GlusterFileSystem) fileSystem), hidden));
54 | System.out.println("Is " + hidden + " hidden? " + isHidden);
55 |
56 | hidden = "/foo/bar";
57 | isHidden = fileSystem.provider().isHidden(new GlusterPath(((GlusterFileSystem) fileSystem), hidden));
58 | System.out.println("Is " + hidden + " hidden? " + isHidden);
59 |
60 | Set posixFilePermissions = PosixFilePermissions.fromString("rw-rw-rw-");
61 | FileAttribute> attrs = PosixFilePermissions.asFileAttribute(posixFilePermissions);
62 |
63 | Path glusterPath = Paths.get(new URI(testUri));
64 | System.out.println(glusterPath.getClass());
65 | System.out.println(glusterPath);
66 | System.out.println(glusterPath.getFileSystem().toString());
67 |
68 | try {
69 | Files.createFile(glusterPath, attrs);
70 | System.out.println("File created");
71 | } catch (IOException e) {
72 | System.out.println("File exists, created at " + Files.getLastModifiedTime(glusterPath));
73 | }
74 | String hello = "Hello, ";
75 | Files.write(glusterPath, hello.getBytes(), StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);
76 | String world = "world!";
77 | Files.write(glusterPath, world.getBytes(), StandardOpenOption.WRITE, StandardOpenOption.APPEND);
78 | long bazSize = Files.size(glusterPath);
79 | System.out.println("SIZE: " + bazSize);
80 | byte[] readBytes = Files.readAllBytes(glusterPath);
81 | System.out.println(hello + world + " == " + new String(readBytes));
82 | System.out.println("Last modified: " + Files.getLastModifiedTime(glusterPath) + " (should be now)");
83 | fileSystem.provider().checkAccess(glusterPath, AccessMode.READ, AccessMode.WRITE);
84 | System.out.println("Can read & write file");
85 | try {
86 | fileSystem.provider().checkAccess(glusterPath, AccessMode.EXECUTE);
87 | System.out.println("Uh oh, file is executable, that's bad.");
88 | } catch (AccessDeniedException e) {
89 | System.out.println("Can't execute file, that's good.");
90 | }
91 |
92 | Path symlinkPath = Paths.get(new URI(mountUri + "symlink"));
93 | Path symlinkTarget = Paths.get(new URI(mountUri + "symlinktarget"));
94 | Files.createSymbolicLink(symlinkPath, symlinkTarget);
95 | System.out.println("SYMLINK: " + symlinkPath.toString() + " => " + Files.readSymbolicLink(symlinkPath));
96 |
97 | Path copyPath = glusterPath.resolveSibling("copy");
98 | // Files.createFile(copyPath, PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rw-rw-rw-")));
99 | Files.copy(glusterPath, copyPath, StandardCopyOption.REPLACE_EXISTING);
100 | long copySize = Files.size(copyPath);
101 | System.out.println("Source and copy are " + (bazSize == copySize ? "" : "NOT") + " equal.");
102 |
103 | try {
104 | Files.newDirectoryStream(mountPath.resolve("bazzzzz"));
105 | } catch (NotDirectoryException e) {
106 | System.out.println("Can't list directory of a file, good.");
107 | }
108 | DirectoryStream.Filter super Path> filter = new DirectoryStream.Filter() {
109 | @Override
110 | public boolean accept(Path entry) throws IOException {
111 | return entry.endsWith("1");
112 | }
113 | };
114 | DirectoryStream stream = Files.newDirectoryStream(mountPath, filter);
115 | System.out.println("Mount contents:");
116 |
117 | for (Path p : stream) {
118 | System.out.println(p.toString());
119 | }
120 |
121 | filter = new DirectoryStream.Filter() {
122 | @Override
123 | public boolean accept(Path entry) throws IOException {
124 | return entry.endsWith("a");
125 | }
126 | };
127 | stream = Files.newDirectoryStream(mountPath, filter);
128 | System.out.println("Mount contents:");
129 |
130 | for (Path p : stream) {
131 | System.out.println(p.toString());
132 | }
133 |
134 | stream = Files.newDirectoryStream(mountPath);
135 | System.out.println("Mount contents:");
136 |
137 | PathMatcher matcher = fileSystem.getPathMatcher("glob:**/*z");
138 | for (Path p : stream) {
139 | System.out.println(p.toString());
140 | if (matcher.matches(p)) {
141 | System.out.println(" **** MATCH ****");
142 | }
143 | }
144 |
145 | stream = Files.newDirectoryStream(mountPath, "*z");
146 | System.out.println("Mount contents:");
147 |
148 | for (Path p : stream) {
149 | System.out.println(p.toString());
150 | }
151 |
152 | WatchService watchService = fileSystem.newWatchService();
153 | Path one = Paths.get(new URI("gluster://" + vagrantBox + ":" + volname + "/one"));
154 |
155 | System.out.println("STARTSWITH empty: " + one.startsWith("/"));
156 | one.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE);
157 | for (int i = 0; i < 10; i++) {
158 | WatchKey take = watchService.poll(1, TimeUnit.SECONDS);
159 | if (null == take) {
160 | continue;
161 | }
162 | List> events = take.pollEvents();
163 | for (WatchEvent e : events) {
164 | Path path = (Path) e.context();
165 | Path absolutePath = one.resolve(path).toAbsolutePath();
166 | boolean exists = Files.exists(absolutePath);
167 | System.out.println("EXISTS? " + exists);
168 | if (exists) {
169 | System.out.println("SIZE: " + Files.size(absolutePath));
170 | }
171 | System.out.println(absolutePath);
172 | System.out.println(e.toString());
173 | }
174 | take.reset();
175 | }
176 |
177 | fileSystem.close();
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem-example/src/main/resources/example.properties:
--------------------------------------------------------------------------------
1 | glusterfs.server=${glusterfs.server}
2 | glusterfs.volume=${glusterfs.volume}
3 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem-example/src/test/java/ExampleTest.java:
--------------------------------------------------------------------------------
1 | import com.peircean.glusterfs.example.Example;
2 | import junit.framework.TestCase;
3 | import org.junit.Test;
4 |
5 | /**
6 | * @author Louis Zuckerman
7 | */
8 | public class ExampleTest extends TestCase {
9 |
10 | @Test
11 | public void testGetProvider() {
12 | Example.getProvider("gluster");
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/NOTICE.txt:
--------------------------------------------------------------------------------
1 | This product includes software developed by The Apache Software
2 | Foundation (http://www.apache.org/).
3 |
4 | [ src/main/java/com/peircean/glusterfs/borrowed/GlobPattern.java:
5 | Trivial changes only. See comments in top of that file for details.
6 | -Louis Zuckerman ]
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | glusterfs-java-filesystem-project
5 | com.peircean.glusterfs
6 | 1.0.5-SNAPSHOT
7 |
8 | 4.0.0
9 |
10 | glusterfs-java-filesystem
11 |
12 |
13 | 1.5.2
14 |
15 |
16 |
17 |
18 |
19 | org.apache.maven.plugins
20 | maven-surefire-plugin
21 | 2.16
22 |
23 | true
24 | once
25 | -ea
26 | true
27 | ${project.build.directory}
28 |
29 | **/*Test.java
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | com.peircean.libgfapi-jni
39 | libgfapi-all
40 | 1.0.5-SNAPSHOT
41 |
42 |
43 |
44 | org.projectlombok
45 | lombok
46 | 1.16.10
47 | provided
48 |
49 |
50 |
51 | org.mockito
52 | mockito-core
53 | 1.9.5
54 | test
55 |
56 |
57 |
58 | org.powermock
59 | powermock-module-junit4
60 | ${powermock.version}
61 | test
62 |
63 |
64 |
65 | org.powermock
66 | powermock-api-mockito
67 | ${powermock.version}
68 | test
69 |
70 |
71 |
72 |
73 |
74 | sonar
75 |
76 |
77 |
78 | com.atlassian.maven.plugins
79 | maven-clover2-plugin
80 | 4.0.2
81 |
82 | ${clover.licenseLocation}
83 |
84 | **/*.java
85 |
86 |
87 | **/borrowed/*.java
88 | **/*Test.java
89 |
90 | ${project.build.directory}/site/clover/clover.xml
91 | ${project.build.directory}/surefire-reports
92 |
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/sonar.txt:
--------------------------------------------------------------------------------
1 | # Run clover & sonar analyses separately
2 | mvn -Psonar clean clover2:setup test clover2:aggregate clover2:clover
3 | mvn -Psonar sonar:sonar
4 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/main/java/com/peircean/glusterfs/GlusterDirectoryIterator.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import com.peircean.libgfapi_jni.internal.GLFS;
4 | import com.peircean.libgfapi_jni.internal.structs.dirent;
5 | import lombok.Data;
6 |
7 | import java.io.IOException;
8 | import java.nio.file.DirectoryStream;
9 | import java.nio.file.Path;
10 | import java.util.Iterator;
11 | import java.util.NoSuchElementException;
12 |
13 | @Data
14 | class GlusterDirectoryIterator implements Iterator {
15 | private GlusterDirectoryStream stream;
16 | private DirectoryStream.Filter super Path> filter;
17 | private dirent current, next;
18 | private GlusterPath nextPath;
19 |
20 | @Override
21 | public boolean hasNext() {
22 | advance();
23 | if (null != filter) {
24 | try {
25 | while (next.d_ino != 0 && !filter.accept(nextPath)) {
26 | advance();
27 | }
28 | } catch (IOException e) {
29 | current = null;
30 | next = null;
31 | return false;
32 | }
33 | }
34 |
35 | if (next != null && next.d_ino == 0) {
36 | current = null;
37 | next = null;
38 | return false;
39 | }
40 |
41 | return true;
42 | }
43 |
44 | void advance() {
45 | String name;
46 | do {
47 | current = new dirent();
48 | long nextPtr = dirent.malloc(dirent.SIZE_OF);
49 | GLFS.glfs_readdir_r(stream.getDirHandle(), current, nextPtr);
50 |
51 | next = new dirent();
52 | dirent.memmove(next, nextPtr, dirent.SIZE_OF);
53 | dirent.free(nextPtr);
54 |
55 | name = current.getName();
56 | nextPath = (GlusterPath) stream.getDir().resolve(name);
57 | } while (name.equals(".") || name.equals(".."));
58 | }
59 |
60 | @Override
61 | public GlusterPath next() {
62 | if (nextPath == null) {
63 | throw new NoSuchElementException("No more entries");
64 | }
65 |
66 | return nextPath;
67 | }
68 |
69 | @Override
70 | public void remove() {
71 | throw new UnsupportedOperationException();
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/main/java/com/peircean/glusterfs/GlusterDirectoryStream.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import com.peircean.libgfapi_jni.internal.GLFS;
4 | import lombok.Data;
5 |
6 | import java.io.IOException;
7 | import java.nio.file.DirectoryStream;
8 | import java.nio.file.Path;
9 | import java.util.Iterator;
10 |
11 | @Data
12 | public class GlusterDirectoryStream implements DirectoryStream {
13 | private GlusterFileSystem fileSystem;
14 | private long dirHandle = 0;
15 | private GlusterDirectoryIterator iterator;
16 | private boolean closed = false;
17 | private GlusterPath dir;
18 | private DirectoryStream.Filter super Path> filter;
19 |
20 | @Override
21 | public Iterator iterator() {
22 | if (null != iterator || closed) {
23 | throw new IllegalStateException("Already iterating!");
24 | }
25 | GlusterDirectoryIterator iterator = new GlusterDirectoryIterator();
26 | iterator.setStream(this);
27 | iterator.setFilter(filter);
28 | this.iterator = iterator;
29 | return iterator;
30 | }
31 |
32 | @Override
33 | public void close() throws IOException {
34 | if (!closed) {
35 | GLFS.glfs_close(dirHandle);
36 | closed = true;
37 | }
38 | }
39 |
40 | public void open(GlusterPath path) {
41 | dir = path;
42 | if (dirHandle == 0) {
43 | dirHandle = GLFS.glfs_opendir(path.getFileSystem().getVolptr(), path.getString());
44 | } else {
45 | throw new IllegalStateException("Already open!");
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/main/java/com/peircean/glusterfs/GlusterFileAttributes.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import lombok.Data;
4 | import com.peircean.libgfapi_jni.internal.structs.stat;
5 |
6 | import java.nio.file.attribute.*;
7 | import java.util.HashMap;
8 | import java.util.HashSet;
9 | import java.util.Map;
10 | import java.util.Set;
11 |
12 | @Data
13 | public class GlusterFileAttributes implements PosixFileAttributes {
14 | private static Map modeToPerms = new HashMap();
15 | private static Map permsToMode;
16 |
17 | static {
18 | modeToPerms.put(0001, PosixFilePermission.OTHERS_EXECUTE);
19 | modeToPerms.put(0002, PosixFilePermission.OTHERS_WRITE);
20 | modeToPerms.put(0004, PosixFilePermission.OTHERS_READ);
21 | modeToPerms.put(0010, PosixFilePermission.GROUP_EXECUTE);
22 | modeToPerms.put(0020, PosixFilePermission.GROUP_WRITE);
23 | modeToPerms.put(0040, PosixFilePermission.GROUP_READ);
24 | modeToPerms.put(0100, PosixFilePermission.OWNER_EXECUTE);
25 | modeToPerms.put(0200, PosixFilePermission.OWNER_WRITE);
26 | modeToPerms.put(0400, PosixFilePermission.OWNER_READ);
27 |
28 | permsToMode = invertModeMap(modeToPerms);
29 | }
30 |
31 | private final int mode, uid, gid;
32 | private final long size, atime, ctime, mtime, inode;
33 |
34 | public static GlusterFileAttributes fromStat(stat stat) {
35 | return new GlusterFileAttributes(stat.st_mode, stat.st_uid, stat.st_gid, stat.st_size,
36 | stat.atime, stat.ctime, stat.mtime, stat.st_ino);
37 | }
38 |
39 | public static int parseAttrs(FileAttribute>... attrs) {
40 | int mode = 0;
41 | for (FileAttribute a : attrs) {
42 | for (PosixFilePermission p : (Set) a.value()) {
43 |
44 | Integer perm = permsToMode.get(p);
45 |
46 | if (null != perm) {
47 | mode |= perm;
48 | }
49 | }
50 | }
51 | return mode;
52 | }
53 |
54 | private static Map invertModeMap(Map modeToPerms) {
55 |
56 | HashMap permsToMode = new HashMap<>();
57 |
58 | for(Map.Entry entry : modeToPerms.entrySet()) {
59 | permsToMode.put(entry.getValue(), entry.getKey());
60 | }
61 |
62 | return permsToMode;
63 | }
64 |
65 | @Override
66 | public UserPrincipal owner() {
67 | return new UserPrincipal() {
68 | @Override
69 | public String getName() {
70 | return String.valueOf(uid);
71 | }
72 | };
73 | }
74 |
75 | @Override
76 | public GroupPrincipal group() {
77 | return new GroupPrincipal() {
78 | @Override
79 | public String getName() {
80 | return String.valueOf(gid);
81 | }
82 | };
83 | }
84 |
85 | @Override
86 | public Set permissions() {
87 | Set permissions = new HashSet();
88 | for (int mask : modeToPerms.keySet()) {
89 | if (mask == (mode & mask)) {
90 | permissions.add(modeToPerms.get(mask));
91 | }
92 | }
93 | return permissions;
94 | }
95 |
96 | @Override
97 | public FileTime lastModifiedTime() {
98 | return FileTime.fromMillis(mtime * 1000);
99 | }
100 |
101 | @Override
102 | public FileTime lastAccessTime() {
103 | return FileTime.fromMillis(atime * 1000);
104 | }
105 |
106 | @Override
107 | public FileTime creationTime() {
108 | return FileTime.fromMillis(ctime * 1000);
109 | }
110 |
111 | @Override
112 | public boolean isRegularFile() {
113 | int mask = 0100000;
114 | return mask == (mode & mask);
115 | }
116 |
117 | @Override
118 | public boolean isDirectory() {
119 | int mask = 0040000;
120 | return mask == (mode & mask);
121 | }
122 |
123 | @Override
124 | public boolean isSymbolicLink() {
125 | int mask = 0120000;
126 | return mask == (mode & mask);
127 | }
128 |
129 | @Override
130 | public boolean isOther() {
131 | return !(isDirectory() || isRegularFile() || isSymbolicLink());
132 | }
133 |
134 | @Override
135 | public long size() {
136 | return size;
137 | }
138 |
139 | @Override
140 | public Object fileKey() {
141 | return inode;
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/main/java/com/peircean/glusterfs/GlusterFileChannel.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import com.peircean.libgfapi_jni.internal.GLFS;
4 | import com.peircean.libgfapi_jni.internal.GlusterOpenOption;
5 | import com.peircean.libgfapi_jni.internal.UtilJNI;
6 | import com.peircean.libgfapi_jni.internal.structs.stat;
7 | import lombok.AccessLevel;
8 | import lombok.Data;
9 | import lombok.NoArgsConstructor;
10 |
11 | import java.io.IOException;
12 | import java.nio.ByteBuffer;
13 | import java.nio.MappedByteBuffer;
14 | import java.nio.channels.*;
15 | import java.nio.file.FileAlreadyExistsException;
16 | import java.nio.file.OpenOption;
17 | import java.nio.file.Path;
18 | import java.nio.file.StandardOpenOption;
19 | import java.nio.file.attribute.FileAttribute;
20 | import java.nio.file.attribute.PosixFilePermission;
21 | import java.util.*;
22 |
23 | /**
24 | * @author Louis Zuckerman
25 | */
26 | @Data
27 | @NoArgsConstructor(access = AccessLevel.PACKAGE)
28 | public class GlusterFileChannel extends FileChannel {
29 | public static final Map optionMap = new HashMap();
30 | public static final Map perms = new HashMap();
31 |
32 | static {
33 | optionMap.put(StandardOpenOption.APPEND, GlusterOpenOption.O_APPEND);
34 | optionMap.put(StandardOpenOption.CREATE, GlusterOpenOption.O_CREAT);
35 | optionMap.put(StandardOpenOption.CREATE_NEW, GlusterOpenOption.O_CREAT | GlusterOpenOption.O_EXCL);
36 | optionMap.put(StandardOpenOption.DSYNC, GlusterOpenOption.O_DSYNC);
37 | optionMap.put(StandardOpenOption.READ, GlusterOpenOption.O_RDONLY);
38 | optionMap.put(StandardOpenOption.WRITE, GlusterOpenOption.O_RDWR);
39 | optionMap.put(StandardOpenOption.TRUNCATE_EXISTING, GlusterOpenOption.O_TRUNC);
40 |
41 | perms.put(PosixFilePermission.OTHERS_EXECUTE, 0001);
42 | perms.put(PosixFilePermission.OTHERS_WRITE, 0002);
43 | perms.put(PosixFilePermission.OTHERS_READ, 0004);
44 | perms.put(PosixFilePermission.GROUP_EXECUTE, 0010);
45 | perms.put(PosixFilePermission.GROUP_WRITE, 0020);
46 | perms.put(PosixFilePermission.GROUP_READ, 0040);
47 | perms.put(PosixFilePermission.OWNER_EXECUTE, 0100);
48 | perms.put(PosixFilePermission.OWNER_WRITE, 0200);
49 | perms.put(PosixFilePermission.OWNER_READ, 0400);
50 | }
51 |
52 | private GlusterFileSystem fileSystem;
53 | private GlusterPath path;
54 | private Set extends OpenOption> options = new HashSet<>();
55 | private FileAttribute> attrs[] = null;
56 | private long fileptr;
57 | private long position;
58 | private boolean closed = false;
59 |
60 | void init(GlusterFileSystem fileSystem, Path path, Set extends OpenOption> options, FileAttribute>... attrs) throws IOException {
61 | this.fileSystem = fileSystem;
62 | if (!path.isAbsolute()) {
63 | throw new IllegalStateException("Only absolute paths are supported at this time");
64 | }
65 | this.path = (GlusterPath) path;
66 | this.options = options;
67 |
68 | int flags = parseOptions(options);
69 | int mode = GlusterFileAttributes.parseAttrs(attrs);
70 |
71 | String pathString = path.toUri().getPath();
72 | boolean createNew = options.contains(StandardOpenOption.CREATE_NEW);
73 | if (options.contains(StandardOpenOption.CREATE) || createNew) {
74 | fileptr = GLFS.glfs_creat(fileSystem.getVolptr(), pathString, flags, mode);
75 | }
76 |
77 | if (createNew && 0 == fileptr) {
78 | throw new FileAlreadyExistsException(path.toString());
79 | }
80 |
81 | if (0 >= fileptr) {
82 | fileptr = GLFS.glfs_open(fileSystem.getVolptr(), pathString, flags);
83 | }
84 |
85 | if (0 >= fileptr) {
86 | throw new IOException("Unable to create or open file '" + pathString + "' on volume '" + fileSystem.toString() + "'");
87 | }
88 | }
89 |
90 | int parseOptions(Set extends OpenOption> options) {
91 | int opt = 0;
92 | for (OpenOption o : options) {
93 | if (!optionMap.containsKey(o)) {
94 | throw new UnsupportedOperationException("Option " + o + " is not supported at this time");
95 | }
96 | opt |= optionMap.get(o);
97 | }
98 | return opt;
99 | }
100 |
101 | @Override
102 | public int read(ByteBuffer byteBuffer) throws IOException {
103 | guardClosed();
104 | byte[] bytes = byteBuffer.array();
105 | long read = GLFS.glfs_read(fileptr, bytes, bytes.length, 0);
106 | if (read < 0) {
107 | throw new IOException(UtilJNI.strerror());
108 | }
109 | position += read;
110 | byteBuffer.position((int)read);
111 | return (int) read;
112 | }
113 |
114 | @Override
115 | public long read(ByteBuffer[] byteBuffers, int offset, int length) throws IOException {
116 | guardClosed();
117 | if (length < 0 || length > byteBuffers.length - offset) {
118 | throw new IndexOutOfBoundsException("Length provided is invalid.");
119 | }
120 | if (offset < 0 || offset > byteBuffers.length) {
121 | throw new IndexOutOfBoundsException("Offset provided is invalid.");
122 | }
123 | if (!options.contains(StandardOpenOption.READ)) {
124 | throw new NonReadableChannelException();
125 | }
126 |
127 | long totalRead = 0L;
128 | try {
129 | totalRead = readHelper(byteBuffers, offset, length);
130 | } finally {
131 | if (totalRead > 0) {
132 | position += totalRead;
133 | }
134 | }
135 | return totalRead;
136 | }
137 |
138 | long readHelper(ByteBuffer[] byteBuffers, int offset, int length) throws IOException {
139 | long totalRead = 0L;
140 | boolean endOfStream = false;
141 | for (int i = offset; i < length + offset && !endOfStream; i++) {
142 | byte[] bytes = byteBuffers[i].array();
143 | int remaining;
144 | while ((remaining = byteBuffers[i].remaining()) > 0) {
145 | long read = GLFS.glfs_read(fileptr, bytes, remaining, 0);
146 | if (read < 0) {
147 | throw new IOException(UtilJNI.strerror());
148 | }
149 | totalRead += read;
150 | byteBuffers[i].position((int) read);
151 | if (0 == read) {
152 | endOfStream = true;
153 | break;
154 | }
155 | }
156 | }
157 |
158 | if (endOfStream && totalRead == 0) {
159 | return -1;
160 | }
161 |
162 | return totalRead;
163 | }
164 |
165 | @Override
166 | public int write(ByteBuffer byteBuffer) throws IOException {
167 | guardClosed();
168 | byte[] buf = byteBuffer.array();
169 | int written = GLFS.glfs_write(fileptr, buf, buf.length, 0);
170 | if (written < 0) {
171 | throw new IOException(UtilJNI.strerror());
172 | }
173 | position += written;
174 | byteBuffer.position(written);
175 | return written;
176 | }
177 |
178 | @Override
179 | public long write(ByteBuffer[] byteBuffers, int offset, int length) throws IOException {
180 | guardClosed();
181 | if (offset < 0 || offset > byteBuffers.length) {
182 | throw new IndexOutOfBoundsException("Offset provided is invalid.");
183 | }
184 | if (length < 0 || length > byteBuffers.length - offset) {
185 | throw new IndexOutOfBoundsException("Length provided is invalid");
186 | }
187 | if (!options.contains(StandardOpenOption.WRITE)) {
188 | throw new NonWritableChannelException();
189 | }
190 |
191 | long totalWritten = 0L;
192 |
193 | for (int i = offset; i < length + offset; i++) {
194 | int remaining = byteBuffers[i].remaining();
195 | while (remaining > 0) {
196 | byte[] bytes = byteBuffers[i].array();
197 | int written = GLFS.glfs_write(fileptr, bytes, remaining, 0);
198 | if (written < 0) {
199 | throw new IOException();
200 | }
201 | position += written;
202 | byteBuffers[i].position(written);
203 | totalWritten += written;
204 | remaining = byteBuffers[i].remaining();
205 | }
206 | }
207 | return totalWritten;
208 | }
209 |
210 | @Override
211 | public long position() throws IOException {
212 | guardClosed();
213 | return position;
214 | }
215 |
216 | @Override
217 | public FileChannel position(long offset) throws IOException {
218 | guardClosed();
219 | if (offset < 0) {
220 | throw new IllegalArgumentException("offset can't be negative");
221 | }
222 | int whence = 0; //SEEK_SET
223 | int seek = GLFS.glfs_lseek(fileptr, offset, whence);
224 | position = offset;
225 | return this;
226 | }
227 |
228 | void guardClosed() throws ClosedChannelException {
229 | if (closed) {
230 | throw new ClosedChannelException();
231 | }
232 | }
233 |
234 | @Override
235 | public long size() throws IOException {
236 | stat stat = new stat();
237 | int retval = GLFS.glfs_fstat(fileptr, stat);
238 | if (0 != retval) {
239 | throw new IOException("fstat failed");
240 | }
241 | return stat.st_size;
242 | }
243 |
244 | @Override
245 | public FileChannel truncate(long l) throws IOException {
246 | return null; //To change body of implemented methods use File | Settings | File Templates.
247 | }
248 |
249 | @Override
250 | public void force(boolean b) throws IOException {
251 | guardClosed();
252 | int fsync = GLFS.glfs_fsync(fileptr);
253 | if (0 != fsync) {
254 | throw new IOException("Unable to fsync");
255 | }
256 | }
257 |
258 | @Override
259 | public long transferTo(long l, long l2, WritableByteChannel writableByteChannel) throws IOException {
260 | return 0; //To change body of implemented methods use File | Settings | File Templates.
261 | }
262 |
263 | @Override
264 | public long transferFrom(ReadableByteChannel readableByteChannel, long l, long l2) throws IOException {
265 | return 0; //To change body of implemented methods use File | Settings | File Templates.
266 | }
267 |
268 | @Override
269 | public int read(ByteBuffer byteBuffer, long position) throws IOException {
270 | guardClosed();
271 | if (position < 0) {
272 | throw new IllegalArgumentException();
273 | }
274 | if (!options.contains(StandardOpenOption.READ)) {
275 | throw new NonReadableChannelException();
276 | }
277 | if (position >= size()) {
278 | return -1;
279 | }
280 | int whence = 0; //SEEK_SET
281 | int seek = GLFS.glfs_lseek(fileptr, position, whence);
282 | if (seek < 0) {
283 | throw new IOException();
284 | }
285 | byte[] bytes = byteBuffer.array();
286 | long read = GLFS.glfs_read(fileptr, bytes, bytes.length, 0);
287 |
288 | if (0 > read) {
289 | throw new IOException();
290 | }
291 |
292 | seek = GLFS.glfs_lseek(fileptr, this.position, whence);
293 |
294 | if (0 > seek) {
295 | throw new IOException(UtilJNI.strerror());
296 | }
297 |
298 | return (int) read;
299 | }
300 |
301 | @Override
302 | public int write(ByteBuffer byteBuffer, long position) throws IOException {
303 | guardClosed();
304 | if (position < 0) {
305 | throw new IllegalArgumentException();
306 | }
307 | if (!options.contains(StandardOpenOption.WRITE)) {
308 | throw new NonWritableChannelException();
309 | }
310 | if (position >= size()) {
311 | byte[] bytes = byteBuffer.array();
312 | byte[] temp = Arrays.copyOf(bytes, bytes.length + (int) (position - size()));
313 | byteBuffer = ByteBuffer.wrap(temp);
314 | }
315 | int whence = 0; //SEEK_SET
316 | int seek = GLFS.glfs_lseek(fileptr, position, whence);
317 | if (seek < 0) {
318 | throw new IOException();
319 | }
320 | byte[] bytes = byteBuffer.array();
321 | long written = GLFS.glfs_write(fileptr, bytes, bytes.length, 0);
322 | seek = GLFS.glfs_lseek(fileptr, this.position, whence);
323 | if (seek < 0) {
324 | throw new IOException();
325 | }
326 | return (int) written;
327 | }
328 |
329 | @Override
330 | public MappedByteBuffer map(MapMode mapMode, long l, long l2) throws IOException {
331 | return null; //To change body of implemented methods use File | Settings | File Templates.
332 | }
333 |
334 | @Override
335 | public FileLock lock(long l, long l2, boolean b) throws IOException {
336 | return null; //To change body of implemented methods use File | Settings | File Templates.
337 | }
338 |
339 | @Override
340 | public FileLock tryLock(long l, long l2, boolean b) throws IOException {
341 | return null; //To change body of implemented methods use File | Settings | File Templates.
342 | }
343 |
344 | @Override
345 | protected void implCloseChannel() throws IOException {
346 | if (!closed) {
347 | int close = GLFS.glfs_close(fileptr);
348 | if (0 != close) {
349 | throw new IOException("Close returned nonzero");
350 | }
351 | closed = true;
352 | }
353 | }
354 |
355 | }
356 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/main/java/com/peircean/glusterfs/GlusterFileStore.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import lombok.AccessLevel;
4 | import lombok.Data;
5 | import lombok.NonNull;
6 | import lombok.RequiredArgsConstructor;
7 |
8 | import java.io.IOException;
9 | import java.nio.file.FileStore;
10 | import java.nio.file.attribute.FileAttributeView;
11 | import java.nio.file.attribute.FileStoreAttributeView;
12 |
13 | /**
14 | * @author Louis Zuckerman
15 | */
16 | @Data
17 | @RequiredArgsConstructor(access = AccessLevel.PACKAGE)
18 | public class GlusterFileStore extends FileStore {
19 | public static final String GLUSTERFS = "glusterfs";
20 | @NonNull
21 | private GlusterFileSystem fileSystem;
22 |
23 | @Override
24 | public String name() {
25 | return fileSystem.getVolname();
26 | }
27 |
28 | @Override
29 | public String type() {
30 | return GLUSTERFS;
31 | }
32 |
33 | @Override
34 | public boolean isReadOnly() {
35 | return false;
36 | }
37 |
38 | @Override
39 | public long getTotalSpace() throws IOException {
40 | GlusterFileSystemProvider provider = (GlusterFileSystemProvider) fileSystem.provider();
41 | return provider.getTotalSpace(fileSystem.getVolptr());
42 | }
43 |
44 | @Override
45 | public long getUsableSpace() throws IOException {
46 | GlusterFileSystemProvider provider = (GlusterFileSystemProvider) fileSystem.provider();
47 | return provider.getUsableSpace(fileSystem.getVolptr());
48 | }
49 |
50 | @Override
51 | public long getUnallocatedSpace() throws IOException {
52 | GlusterFileSystemProvider provider = (GlusterFileSystemProvider) fileSystem.provider();
53 | return provider.getUnallocatedSpace(fileSystem.getVolptr());
54 | }
55 |
56 | @Override
57 | public boolean supportsFileAttributeView(Class extends FileAttributeView> aClass) {
58 | throw new UnsupportedOperationException();
59 | }
60 |
61 | @Override
62 | public boolean supportsFileAttributeView(String s) {
63 | throw new UnsupportedOperationException();
64 | }
65 |
66 | @Override
67 | public V getFileStoreAttributeView(Class vClass) {
68 | throw new UnsupportedOperationException();
69 | }
70 |
71 | @Override
72 | public Object getAttribute(String s) throws IOException {
73 | throw new UnsupportedOperationException();
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/main/java/com/peircean/glusterfs/GlusterFileSystem.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import com.peircean.glusterfs.borrowed.GlobPattern;
4 | import lombok.*;
5 |
6 | import java.io.IOException;
7 | import java.nio.file.*;
8 | import java.nio.file.attribute.UserPrincipalLookupService;
9 | import java.nio.file.spi.FileSystemProvider;
10 | import java.util.ArrayList;
11 | import java.util.Collections;
12 | import java.util.List;
13 | import java.util.Set;
14 | import java.util.regex.Pattern;
15 |
16 | /**
17 | * @author Louis Zuckerman
18 | */
19 | @Getter(AccessLevel.PACKAGE)
20 | @Setter(AccessLevel.PACKAGE)
21 | @EqualsAndHashCode(exclude = {"provider", "volptr"}, callSuper = false)
22 | @RequiredArgsConstructor(access = AccessLevel.PACKAGE)
23 | public class GlusterFileSystem extends FileSystem {
24 | private static final String SEPARATOR = "/";
25 | @NonNull
26 | private final GlusterFileSystemProvider provider;
27 | @NonNull
28 | private final String host;
29 | @NonNull
30 | private final String volname;
31 | @NonNull
32 | private long volptr;
33 |
34 | @Override
35 | public FileSystemProvider provider() {
36 | return provider;
37 | }
38 |
39 | @Override
40 | public void close() throws IOException {
41 | if (isOpen()) {
42 | int fini = provider.close(volptr);
43 | if (0 != fini) {
44 | throw new IOException("Unable to close filesystem: " + volname);
45 | }
46 | volptr = -1;
47 | }
48 | }
49 |
50 | @Override
51 | public boolean isOpen() {
52 | return volptr > 0;
53 | }
54 |
55 | @Override
56 | public boolean isReadOnly() {
57 | return false;
58 | }
59 |
60 | @Override
61 | public String getSeparator() {
62 | return SEPARATOR;
63 | }
64 |
65 | @Override
66 | public Iterable getRootDirectories() {
67 | GlusterPath root = new GlusterPath(this, "/");
68 | List list = new ArrayList(1);
69 | list.add(root);
70 | return Collections.unmodifiableList(list);
71 | }
72 |
73 | @Override
74 | public Iterable getFileStores() {
75 | GlusterFileStore store = new GlusterFileStore(this);
76 | List stores = new ArrayList(1);
77 | stores.add(store);
78 | return Collections.unmodifiableList(stores);
79 | }
80 |
81 | @Override
82 | public Set supportedFileAttributeViews() {
83 | throw new UnsupportedOperationException();
84 | }
85 |
86 | @Override
87 | public Path getPath(String s, String... strings) {
88 | boolean absolute = s.startsWith("/");
89 | if (absolute) {
90 | s = s.substring(1);
91 | }
92 | String[] parts;
93 | if (null != strings && strings.length > 0) {
94 | parts = new String[1 + strings.length];
95 | parts[0] = s;
96 | System.arraycopy(strings, 0, parts, 1, strings.length);
97 | } else {
98 | parts = new String[]{s};
99 | }
100 | return new GlusterPath(this, parts, absolute);
101 | }
102 |
103 | @Override
104 | public PathMatcher getPathMatcher(String s) {
105 | if (!s.contains(":")) {
106 | throw new IllegalArgumentException("PathMatcher requires input syntax:expression");
107 | }
108 | String[] parts = s.split(":", 2);
109 | Pattern pattern;
110 | if ("glob".equals(parts[0])) {
111 | pattern = GlobPattern.compile(parts[1]);
112 | } else if ("regex".equals(parts[0])) {
113 | pattern = Pattern.compile(parts[1]);
114 | } else {
115 | throw new UnsupportedOperationException("Unknown PathMatcher syntax: " + parts[0]);
116 | }
117 |
118 | return new GlusterPathMatcher(pattern);
119 | }
120 |
121 | @Override
122 | public UserPrincipalLookupService getUserPrincipalLookupService() {
123 | throw new UnsupportedOperationException();
124 | }
125 |
126 | @Override
127 | public WatchService newWatchService() throws IOException {
128 | return new GlusterWatchService();
129 | }
130 |
131 | public String toString() {
132 | return provider.getScheme() + "://" + host + ":" + volname;
133 | }
134 | }
135 |
136 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/main/java/com/peircean/glusterfs/GlusterFileSystemProvider.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import com.peircean.libgfapi_jni.internal.GLFS;
4 | import com.peircean.libgfapi_jni.internal.structs.stat;
5 | import com.peircean.libgfapi_jni.internal.structs.statvfs;
6 | import lombok.AccessLevel;
7 | import lombok.Getter;
8 |
9 | import java.io.IOException;
10 | import java.net.URI;
11 | import java.nio.ByteBuffer;
12 | import java.nio.channels.FileChannel;
13 | import java.nio.channels.SeekableByteChannel;
14 | import java.nio.file.*;
15 | import java.nio.file.attribute.*;
16 | import java.nio.file.spi.FileSystemProvider;
17 | import java.util.*;
18 |
19 | import static com.peircean.libgfapi_jni.internal.GLFS.*;
20 |
21 | /**
22 | * @author Louis Zuckerman
23 | */
24 | public class GlusterFileSystemProvider extends FileSystemProvider {
25 |
26 | public static final String GLUSTER = "gluster";
27 | public static final int GLUSTERD_PORT = 24007;
28 | public static final String TCP = "tcp";
29 | @Getter(AccessLevel.PACKAGE)
30 | private static Map cache = new HashMap();
31 |
32 | @Override
33 | public String getScheme() {
34 | return GLUSTER;
35 | }
36 |
37 | @Override
38 | public FileSystem newFileSystem(URI uri, Map stringMap) throws IOException {
39 | String authorityString = uri.getAuthority();
40 | String[] authority = parseAuthority(authorityString);
41 |
42 | String volname = authority[1];
43 | long volptr = glfsNew(volname);
44 |
45 | glfsSetVolfileServer(authority[0], volptr);
46 |
47 | glfsInit(authorityString, volptr);
48 |
49 | // GLFS.glfs_set_logging(volptr, "/tmp/gluster-java.log", 9);
50 |
51 | GlusterFileSystem fileSystem = new GlusterFileSystem(this, authority[0], volname, volptr);
52 | cache.put(authorityString, fileSystem);
53 |
54 | return fileSystem;
55 | }
56 |
57 | String[] parseAuthority(String authority) {
58 | if (!authority.contains(":")) {
59 | throw new IllegalArgumentException("URI must be of the form 'gluster://server:volume/path");
60 | }
61 | String[] aarr = authority.split(":");
62 | if (aarr.length != 2 || aarr[0].isEmpty() || aarr[1].isEmpty()) {
63 | throw new IllegalArgumentException("URI must be of the form 'gluster://server:volume/path");
64 | }
65 |
66 | return aarr;
67 | }
68 |
69 | long glfsNew(String volname) {
70 | long volptr = glfs_new(volname);
71 | if (0 == volptr) {
72 | throw new IllegalArgumentException("Failed to create new client for volume: " + volname);
73 | }
74 | return volptr;
75 | }
76 |
77 | void glfsSetVolfileServer(String host, long volptr) {
78 | int setServer = glfs_set_volfile_server(volptr, TCP, host, GLUSTERD_PORT);
79 | if (0 != setServer) {
80 | throw new IllegalArgumentException("Failed to set server address: " + host);
81 | }
82 | }
83 |
84 | void glfsInit(String authorityString, long volptr) {
85 | int init = glfs_init(volptr);
86 | if (0 != init) {
87 | throw new IllegalArgumentException("Failed to initialize glusterfs client: " + authorityString);
88 | }
89 | }
90 |
91 | @Override
92 | public FileSystem getFileSystem(URI uri) {
93 | if (!cache.containsKey(uri.getAuthority())) {
94 | throw new FileSystemNotFoundException("No cached filesystem for: " + uri.getAuthority());
95 | }
96 | return cache.get(uri.getAuthority());
97 | }
98 |
99 | @Override
100 | public Path getPath(URI uri) {
101 | if (!uri.getScheme().equals(getScheme())) {
102 | throw new IllegalArgumentException("No support for scheme: " + uri.getScheme());
103 | }
104 | try {
105 | FileSystem fileSystem = getFileSystem(uri);
106 | return fileSystem.getPath(uri.getPath());
107 | } catch (FileSystemNotFoundException e) {
108 | }
109 |
110 | try {
111 | return newFileSystem(uri, null).getPath(uri.getPath());
112 | } catch (IOException e) {
113 | throw new FileSystemNotFoundException("Unable to open a connection to " + uri.getAuthority());
114 | }
115 | }
116 |
117 | @Override
118 | public SeekableByteChannel newByteChannel(Path path, Set extends OpenOption> openOptions, FileAttribute>... fileAttributes) throws IOException {
119 | return newFileChannelHelper(path, openOptions, fileAttributes);
120 | }
121 |
122 | @Override
123 | public FileChannel newFileChannel(Path path, Set extends OpenOption> options, FileAttribute>... attrs) throws IOException {
124 | return newFileChannelHelper(path, options, attrs);
125 | }
126 |
127 | FileChannel newFileChannelHelper(Path path, Set extends OpenOption> options, FileAttribute>[] attrs) throws IOException {
128 | GlusterFileChannel channel = new GlusterFileChannel();
129 | channel.init((GlusterFileSystem) getFileSystem(path.toUri()), path, options, attrs);
130 | return channel;
131 | }
132 |
133 | @Override
134 | public DirectoryStream newDirectoryStream(Path path, DirectoryStream.Filter super Path> filter) throws IOException {
135 | if (!Files.isDirectory(path)) {
136 | throw new NotDirectoryException("Not a directory! " + path.toString());
137 | }
138 | GlusterPath glusterPath = (GlusterPath) path;
139 | GlusterDirectoryStream stream = new GlusterDirectoryStream();
140 | stream.setFileSystem(glusterPath.getFileSystem());
141 | stream.open(glusterPath);
142 | stream.setFilter(filter);
143 |
144 | return stream;
145 | }
146 |
147 | @Override
148 | public void createDirectory(Path path, FileAttribute>... fileAttributes) throws IOException {
149 | if (Files.exists(path)) {
150 | throw new FileAlreadyExistsException(path.toString());
151 | }
152 | if (!Files.exists(path.getParent())) {
153 | throw new IOException();
154 | }
155 |
156 | int mode = 0775;
157 |
158 | if (fileAttributes.length > 0) {
159 | mode = GlusterFileAttributes.parseAttrs(fileAttributes);
160 | }
161 |
162 | int ret = GLFS.glfs_mkdir(((GlusterFileSystem) path.getFileSystem()).getVolptr(), path.toString(), mode);
163 |
164 | if (ret < 0) {
165 | throw new IOException(path.toString());
166 | }
167 | }
168 |
169 | @Override
170 | public void delete(Path path) throws IOException {
171 | if (!Files.exists(path)) {
172 | throw new NoSuchFileException(path.toString());
173 | }
174 | if (Files.isDirectory(path)) {
175 | if(!directoryIsEmpty(path)) {
176 | throw new DirectoryNotEmptyException(path.toString());
177 | }
178 |
179 | int ret = GLFS.glfs_rmdir(((GlusterFileSystem)path.getFileSystem()).getVolptr(), path.toString());
180 |
181 | if (ret < 0) {
182 | throw new IOException(path.toString());
183 | }
184 | } else {
185 | int ret = GLFS.glfs_unlink(((GlusterFileSystem) path.getFileSystem()).getVolptr(), path.toString());
186 |
187 | if (ret < 0) {
188 | throw new IOException(path.toString());
189 | }
190 | }
191 | }
192 |
193 | @Override
194 | public void copy(Path path, Path path2, CopyOption... copyOptions) throws IOException {
195 | guardAbsolutePath(path);
196 | guardAbsolutePath(path2);
197 | guardFileExists(path);
198 |
199 | boolean targetExists = Files.exists(path2);
200 | if (targetExists && isSameFile(path, path2)) {
201 | return;
202 | }
203 |
204 | boolean overwrite = false;
205 | boolean copyAttributes = false;
206 | for (CopyOption co : copyOptions) {
207 | if (StandardCopyOption.ATOMIC_MOVE.equals(co)) {
208 | throw new UnsupportedOperationException("Atomic move not supported");
209 | }
210 | if (StandardCopyOption.REPLACE_EXISTING.equals(co)) {
211 | overwrite = true;
212 | }
213 | if (StandardCopyOption.COPY_ATTRIBUTES.equals(co)) {
214 | copyAttributes = true;
215 | }
216 | }
217 |
218 | if (!overwrite && targetExists) {
219 | throw new FileAlreadyExistsException("Target " + path2 + " exists and REPLACE_EXISTING not specified");
220 | }
221 | if (Files.isDirectory(path2) && !directoryIsEmpty(path2)) {
222 | throw new DirectoryNotEmptyException("Target not empty: " + path2);
223 | }
224 | if (Files.isDirectory(path)) {
225 | Files.createDirectory(path2);
226 | } else {
227 | Files.createFile(path2, PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rw-rw-r--")));
228 | copyFileContent(path, path2);
229 | if (copyAttributes) {
230 | copyFileAttributes(path, path2);
231 | }
232 | }
233 | }
234 |
235 | void copyFileAttributes(Path path, Path path2) throws IOException {
236 | stat stat = new stat();
237 | long volptr = ((GlusterFileSystem) path.getFileSystem()).getVolptr();
238 | int retStat = glfs_stat(volptr, path.toString(), stat);
239 | int retChmod = 0;
240 | if (0664 != stat.st_mode) {
241 | retChmod = GLFS.glfs_chmod(volptr, path2.toString(), stat.st_mode);
242 | }
243 | if (retStat < 0 || retChmod < 0) {
244 | throw new IOException("Could not copy file attributes.");
245 | }
246 | }
247 |
248 | void copyFileContent(Path path, Path path2) throws IOException {
249 | Set options = new HashSet<>();
250 | options.add(StandardOpenOption.READ);
251 |
252 | //TODO: investigate 8kB byte array limitation
253 | byte[] readBytes = new byte[8192];
254 | FileChannel channel = newFileChannel(path, options);
255 | ByteBuffer readBuffer = ByteBuffer.wrap(readBytes);
256 |
257 | boolean writtenTo = false;
258 | int read = channel.read(readBuffer);
259 |
260 | while (read > 0) {
261 | byte[] writeBytes = Arrays.copyOf(readBytes, read);
262 | if (!writtenTo) {
263 | Files.write(path2, writeBytes, StandardOpenOption.TRUNCATE_EXISTING);
264 | writtenTo = true;
265 | } else {
266 | Files.write(path2, writeBytes, StandardOpenOption.APPEND);
267 | }
268 | read = channel.read(readBuffer);
269 | }
270 | channel.close();
271 | }
272 |
273 | boolean directoryIsEmpty(Path path) throws IOException {
274 | try (DirectoryStream stream = newDirectoryStream(path, null)) {
275 | if (stream.iterator().hasNext()) {
276 | return false;
277 | }
278 | return true;
279 | }
280 | }
281 |
282 | @Override
283 | public void move(Path path, Path path2, CopyOption... copyOptions) throws IOException {
284 | guardAbsolutePath(path);
285 | guardAbsolutePath(path2);
286 | guardFileExists(path);
287 | if (Files.exists(path2) && isSameFile(path, path2)) {
288 | return;
289 | }
290 |
291 | boolean overwrite = false;
292 | for (CopyOption co : copyOptions) {
293 | if (StandardCopyOption.ATOMIC_MOVE.equals(co)) {
294 | throw new AtomicMoveNotSupportedException(path.toString(), path2.toString(), "Atomic move not supported");
295 | }
296 | if (StandardCopyOption.REPLACE_EXISTING.equals(co)) {
297 | overwrite = true;
298 | }
299 | }
300 |
301 | FileSystem fileSystem = path.getFileSystem();
302 |
303 | if (!overwrite && Files.exists(path2)) {
304 | throw new FileAlreadyExistsException("Target " + path2 + " exists and REPLACE_EXISTING not specified");
305 | }
306 | if (Files.isDirectory(path2) && !directoryIsEmpty(path2)) {
307 | throw new DirectoryNotEmptyException("Target not empty: " + path2);
308 | }
309 | if (!fileSystem.equals(path2.getFileSystem())) {
310 | throw new UnsupportedOperationException("Can not move file to a different file system");
311 | }
312 | GLFS.glfs_rename(((GlusterFileSystem) fileSystem).getVolptr(), ((GlusterPath) path).getString(), ((GlusterPath) path2).getString());
313 | }
314 |
315 | void guardFileExists(Path path) throws NoSuchFileException {
316 | if (!Files.exists(path)) {
317 | throw new NoSuchFileException(path.toString());
318 | }
319 | }
320 |
321 | void guardAbsolutePath(Path p) {
322 | if (!p.isAbsolute()) {
323 | throw new UnsupportedOperationException("Relative paths not supported: " + p);
324 | }
325 | }
326 |
327 | @Override
328 | public boolean isSameFile(Path path, Path path2) throws IOException {
329 | if (path.equals(path2)) {
330 | return true;
331 | }
332 | if (!path.getFileSystem().equals(path2.getFileSystem())) { //if file system differs, then we don't need to check provider; we know the files differ
333 | return false;
334 | }
335 | guardFileExists(path);
336 | guardFileExists(path2);
337 |
338 | stat stat1 = statPath(path);
339 | stat stat2 = statPath(path2);
340 |
341 | return stat1.st_ino == stat2.st_ino;
342 | }
343 |
344 | stat statPath(Path path) throws IOException {
345 | stat stat = new stat();
346 | String pathString = ((GlusterPath) path).getString();
347 | int ret = GLFS.glfs_stat(((GlusterFileSystem) path.getFileSystem()).getVolptr(),
348 | pathString, stat);
349 | if (ret != 0) {
350 | throw new IOException("Stat failed for " + pathString);
351 | }
352 | return stat;
353 | }
354 |
355 | @Override
356 | public boolean isHidden(Path path) throws IOException {
357 | return ((GlusterPath) path.getFileName()).getParts()[0].startsWith(".");
358 | }
359 |
360 | @Override
361 | public FileStore getFileStore(Path path) throws IOException {
362 | if (Files.exists(path)) {
363 | return path.getFileSystem().getFileStores().iterator().next();
364 | } else {
365 | throw new NoSuchFileException(path.toString());
366 | }
367 | }
368 |
369 | @Override
370 | public void checkAccess(Path path, AccessMode... accessModes) throws IOException {
371 | long volptr = ((GlusterFileSystem) path.getFileSystem()).getVolptr();
372 | String pathString = ((GlusterPath) path).getString();
373 |
374 | stat stat = new stat();
375 | int ret = GLFS.glfs_lstat(volptr, pathString, stat);
376 |
377 | if (-1 == ret) {
378 | throw new NoSuchFileException("");
379 | }
380 |
381 | for (AccessMode m : accessModes) {
382 | int access = GLFS.glfs_access(volptr, pathString, modeInt(m));
383 | if (-1 == access) {
384 | throw new AccessDeniedException(pathString);
385 | }
386 | }
387 |
388 | }
389 |
390 | private int modeInt(AccessMode m) {
391 | switch (m) {
392 | case EXECUTE:
393 | return 1;
394 | case WRITE:
395 | return 2;
396 | case READ:
397 | return 4;
398 | }
399 | return -1;
400 | }
401 |
402 | @Override
403 | public V getFileAttributeView(Path path, Class vClass, LinkOption... linkOptions) {
404 | return null;
405 | }
406 |
407 | @Override
408 | public A readAttributes(Path path, Class type, LinkOption... linkOptions) throws IOException {
409 | // if (!type.isAssignableFrom(GlusterFileAttributes.class)) { // Why doesn't this work when type is GlusterFileAttributes.class?!
410 | if (type.equals(DosFileAttributes.class)) {
411 | throw new UnsupportedOperationException(type + " attribute type is not supported, only PosixFileAttributes & its superinterfaces");
412 | }
413 | stat stat = new stat();
414 |
415 | boolean followSymlinks = true;
416 | for (LinkOption lo : linkOptions) {
417 | if (lo.equals(LinkOption.NOFOLLOW_LINKS)) {
418 | followSymlinks = false;
419 | break;
420 | }
421 | }
422 | int ret;
423 | String pathString = ((GlusterPath) path).getString();
424 | if (followSymlinks) {
425 | ret = GLFS.glfs_stat(((GlusterFileSystem) path.getFileSystem()).getVolptr(), pathString, stat);
426 | } else {
427 | ret = GLFS.glfs_lstat(((GlusterFileSystem) path.getFileSystem()).getVolptr(), pathString, stat);
428 | }
429 |
430 | if (-1 == ret) {
431 | throw new NoSuchFileException("");
432 | }
433 |
434 | return (A) GlusterFileAttributes.fromStat(stat);
435 | }
436 |
437 | @Override
438 | public Map readAttributes(Path path, String s, LinkOption... linkOptions) throws IOException {
439 | return null;
440 | }
441 |
442 | @Override
443 | public void setAttribute(Path path, String s, Object o, LinkOption... linkOptions) throws IOException {
444 |
445 | }
446 |
447 | @Override
448 | public Path readSymbolicLink(Path link) throws IOException {
449 | String pathString = link.toString();
450 | if (!Files.isSymbolicLink(link)) {
451 | throw new NotLinkException(pathString);
452 | }
453 |
454 | stat stat = new stat();
455 | GlusterFileSystem fileSystem = (GlusterFileSystem) link.getFileSystem();
456 | long volptr = fileSystem.getVolptr();
457 | int statReturn = GLFS.glfs_lstat(volptr, pathString, stat);
458 | if (0 != statReturn) {
459 | throw new IOException("Unable to get size of symlink " + pathString);
460 | }
461 |
462 | long length = (int) stat.st_size;
463 | byte[] content = new byte[(int)length];
464 | int readReturn = GLFS.glfs_readlink(volptr, pathString, content, content.length);
465 | if (-1 == readReturn) {
466 | throw new IOException("Unable to read symlink " + pathString);
467 | }
468 |
469 | return new GlusterPath(fileSystem, new String(content));
470 | }
471 |
472 | @Override
473 | public void createSymbolicLink(Path link, Path target, FileAttribute>... attrs) throws IOException {
474 | String linkPath = link.toString();
475 | if (Files.exists(link, LinkOption.NOFOLLOW_LINKS)) {
476 | throw new FileAlreadyExistsException(linkPath);
477 | }
478 | if (null != attrs && attrs.length > 0) {
479 | throw new UnsupportedOperationException("glfs_symlink does not support atomic mode/perms");
480 | }
481 | GlusterFileSystem fileSystem = (GlusterFileSystem) link.getFileSystem();
482 | long volptr = fileSystem.getVolptr();
483 | int ret = GLFS.glfs_symlink(volptr, target.toString(), linkPath);
484 | if (0 != ret) {
485 | throw new IOException("Unknown error creating symlink: " + linkPath);
486 | }
487 | }
488 |
489 | int close(long volptr) {
490 | return glfs_fini(volptr);
491 | }
492 |
493 | long getTotalSpace(long volptr) throws IOException {
494 | statvfs buf = new statvfs();
495 | GLFS.glfs_statvfs(volptr, "/", buf);
496 | return buf.f_bsize * buf.f_blocks;
497 | }
498 |
499 | long getUsableSpace(long volptr) throws IOException {
500 | statvfs buf = new statvfs();
501 | GLFS.glfs_statvfs(volptr, "/", buf);
502 | return buf.f_bsize * buf.f_bavail;
503 | }
504 |
505 | long getUnallocatedSpace(long volptr) throws IOException {
506 | statvfs buf = new statvfs();
507 | GLFS.glfs_statvfs(volptr, "/", buf);
508 | return buf.f_bsize * buf.f_bfree;
509 | }
510 | }
511 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/main/java/com/peircean/glusterfs/GlusterPath.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import lombok.Data;
4 | import lombok.EqualsAndHashCode;
5 |
6 | import java.io.File;
7 | import java.io.IOException;
8 | import java.net.URI;
9 | import java.net.URISyntaxException;
10 | import java.nio.file.*;
11 | import java.util.*;
12 |
13 | /**
14 | * @author Louis Zuckerman
15 | */
16 | @Data
17 | @EqualsAndHashCode(exclude = "pathString")
18 | public class GlusterPath implements Path {
19 | private GlusterFileSystem fileSystem;
20 | private String[] parts;
21 | private String pathString;
22 | private boolean absolute;
23 |
24 | public GlusterPath(GlusterFileSystem fileSystem, String path) {
25 | if (null == fileSystem) {
26 | throw new IllegalArgumentException("fileSystem can not be empty");
27 | }
28 | if (null == path) {
29 | throw new InvalidPathException("", "path can not be null");
30 | }
31 | this.fileSystem = fileSystem;
32 | this.pathString = path;
33 |
34 | String stripped = path;
35 | if (path.startsWith(fileSystem.getSeparator())) {
36 | absolute = true;
37 | stripped = stripped.substring(1);
38 | }
39 | if (stripped.endsWith(fileSystem.getSeparator())) {
40 | stripped = stripped.substring(0, stripped.length() - 1);
41 | }
42 | parts = stripped.split(fileSystem.getSeparator());
43 | }
44 |
45 | GlusterPath(GlusterFileSystem fileSystem, String[] parts, boolean absolute) {
46 | this.fileSystem = fileSystem;
47 | this.parts = parts;
48 | this.absolute = absolute;
49 | }
50 |
51 | @Override
52 | public boolean isAbsolute() {
53 | return absolute;
54 | }
55 |
56 | @Override
57 | public Path getRoot() {
58 | if (absolute) {
59 | return fileSystem.getRootDirectories().iterator().next();
60 | } else {
61 | return null;
62 | }
63 | }
64 |
65 | @Override
66 | public Path getFileName() {
67 | if (parts.length == 0 || parts[0].isEmpty()) {
68 | return null;
69 | } else {
70 | return new GlusterPath(fileSystem, parts[parts.length - 1]);
71 | }
72 | }
73 |
74 | @Override
75 | public Path getParent() {
76 | if (parts.length <= 1 || parts[0].isEmpty()) {
77 | if (absolute) {
78 | return getRoot();
79 | } else {
80 | return null;
81 | }
82 | } else {
83 | return new GlusterPath(fileSystem, Arrays.copyOfRange(parts, 0, parts.length - 1), absolute);
84 | }
85 | }
86 |
87 | @Override
88 | public int getNameCount() {
89 | if (parts.length <= 1 && parts[0].isEmpty()) {
90 | if (absolute) {
91 | return 0;
92 | } else {
93 | throw new IllegalStateException("Only the root path should have one empty part");
94 | }
95 | } else {
96 | return parts.length;
97 | }
98 | }
99 |
100 | @Override
101 | public Path getName(int i) {
102 | if (i < 0 || i >= parts.length || (0 == i && parts.length <= 1 && parts[0].isEmpty())) {
103 | throw new IllegalArgumentException("invalid name index");
104 | }
105 | return new GlusterPath(fileSystem, Arrays.copyOfRange(parts, 0, i + 1), absolute);
106 | }
107 |
108 | @Override
109 | public Path subpath(int i, int i2) {
110 | if ((0 == i && parts.length <= 1 && parts[0].isEmpty())
111 | || i < 0 || i2 < 0
112 | || i >= parts.length || i2 > parts.length
113 | || i > i2) {
114 | throw new IllegalArgumentException("invalid indices");
115 | }
116 | return new GlusterPath(fileSystem, Arrays.copyOfRange(parts, i, i2), absolute);
117 | }
118 |
119 | @Override
120 | public boolean startsWith(Path path) {
121 | GlusterPath otherPath = (GlusterPath) path;
122 | if (this.equals(otherPath)) {
123 | return true;
124 | }
125 | if (otherPath.getParts().length > parts.length) {
126 | return false;
127 | }
128 | if (absolute && otherPath.isAbsolute() && otherPath.getParts()[0].isEmpty()) {
129 | return true;
130 | }
131 | String[] thisPrefix = Arrays.copyOfRange(parts, 0, otherPath.getParts().length);
132 | return ((absolute == otherPath.isAbsolute())
133 | && (Arrays.equals(thisPrefix, otherPath.getParts())));
134 | }
135 |
136 | @Override
137 | public boolean startsWith(String s) {
138 | return startsWith(new GlusterPath(fileSystem, s));
139 | }
140 |
141 | @Override
142 | public boolean endsWith(Path path) {
143 | GlusterPath otherPath = (GlusterPath) path;
144 | if (this.equals(otherPath)) {
145 | return true;
146 | }
147 | if (otherPath.getParts().length > parts.length) {
148 | return false;
149 | }
150 | if (absolute && otherPath.isAbsolute() && otherPath.getParts()[0].isEmpty()) {
151 | return true;
152 | }
153 | String[] thisSuffix = Arrays.copyOfRange(parts, parts.length - otherPath.getParts().length, parts.length);
154 | return ((!otherPath.isAbsolute())
155 | && (Arrays.equals(thisSuffix, otherPath.getParts())));
156 | }
157 |
158 | @Override
159 | public boolean endsWith(String s) {
160 | return toString().endsWith(s);
161 | }
162 |
163 | @Override
164 | public Path normalize() {
165 | List newParts = new LinkedList();
166 | for (String part : parts) {
167 | if (part.equals("..")) {
168 | newParts.remove(newParts.size() - 1);
169 | } else if (!part.equals(".") && !part.isEmpty()) {
170 | newParts.add(part);
171 | }
172 | }
173 | return new GlusterPath(fileSystem, newParts.toArray(new String[]{}), absolute);
174 | }
175 |
176 | @Override
177 | public Path resolve(Path path) {
178 | GlusterPath otherPath = (GlusterPath) path;
179 | if (!fileSystem.equals(otherPath.getFileSystem())) {
180 | throw new IllegalArgumentException("Can not resolve other path because it's on a different filesystem");
181 | }
182 |
183 | if (otherPath.isAbsolute() || (absolute && parts.length == 1 && parts[0].isEmpty())) {
184 | return new GlusterPath(fileSystem, otherPath.getParts(), true);
185 | }
186 |
187 | if (otherPath.getParts().length == 1 && otherPath.getParts()[0].isEmpty()) {
188 | return this;
189 | }
190 | String[] newParts = Arrays.copyOf(parts, parts.length + otherPath.getParts().length);
191 | System.arraycopy(otherPath.getParts(), 0, newParts, parts.length, otherPath.getParts().length);
192 | return new GlusterPath(fileSystem, newParts, absolute);
193 | }
194 |
195 | @Override
196 | public Path resolve(String s) {
197 | return resolve(new GlusterPath(fileSystem, s));
198 | }
199 |
200 | @Override
201 | public Path resolveSibling(Path path) {
202 | return getParent().resolve(path);
203 | }
204 |
205 | @Override
206 | public Path resolveSibling(String s) {
207 | return getParent().resolve(s);
208 | }
209 |
210 | @Override
211 | public Path relativize(Path path) {
212 | if (!fileSystem.equals(path.getFileSystem())) {
213 | throw new IllegalArgumentException("Can not relativize other path because it's on a different filesystem");
214 | }
215 |
216 | if (!this.isAbsolute() || !path.isAbsolute()) {
217 | throw new IllegalArgumentException("Can only relativize when both paths are absolute");
218 | }
219 | GlusterPath other = (GlusterPath) path;
220 | List relativeParts = new LinkedList();
221 | boolean stillCommon = true;
222 | int lastCommonName = -1;
223 | for (int i = 0; i < parts.length; i++) {
224 | if (i >= other.getParts().length) {
225 | for (int r = 0; r < other.getParts().length; r++) {
226 | relativeParts.add("..");
227 | }
228 | break;
229 | }
230 | if (stillCommon && parts[i].equals(other.getParts()[i])) {
231 | lastCommonName = i;
232 | } else {
233 | stillCommon = false;
234 | relativeParts.add("..");
235 | }
236 | }
237 | for (int i = lastCommonName + 1; i < other.getParts().length; i++) {
238 | relativeParts.add(other.getParts()[i]);
239 | }
240 | return new GlusterPath(fileSystem, relativeParts.toArray(new String[]{}), false);
241 | }
242 |
243 | @Override
244 | public URI toUri() {
245 | try {
246 | GlusterFileSystem fs = getFileSystem();
247 | String authority = fs.getHost() + ":" + fs.getVolname();
248 | return new URI(fs.provider().getScheme(), authority, toString(), null, null);
249 | } catch (URISyntaxException e) {
250 | throw new IllegalStateException(e);
251 | }
252 | }
253 |
254 | @Override
255 | public Path toAbsolutePath() {
256 | if (!absolute) {
257 | throw new UnsupportedOperationException();
258 | } else {
259 | return this;
260 | }
261 | }
262 |
263 | @Override
264 | public Path toRealPath(LinkOption... linkOptions) throws IOException {
265 | throw new UnsupportedOperationException();
266 | }
267 |
268 | @Override
269 | public File toFile() {
270 | throw new UnsupportedOperationException();
271 | }
272 |
273 | @Override
274 | public WatchKey register(WatchService watchService, WatchEvent.Kind>[] kinds, WatchEvent.Modifier... modifiers) throws IOException {
275 | throw new UnsupportedOperationException("GlusterWatchService does not support modifiers at this time.");
276 | }
277 |
278 | @Override
279 | public WatchKey register(WatchService watchService, WatchEvent.Kind>... kinds) throws IOException {
280 | guardRegisterWatchService(watchService);
281 | guardRegisterWatchDirectory();
282 |
283 | return ((GlusterWatchService) watchService).registerPath(this, kinds);
284 | }
285 |
286 | void guardRegisterWatchDirectory() throws NotDirectoryException {
287 | if (!Files.isDirectory(this)) {
288 | throw new NotDirectoryException("GlusterWatchService can only watch directories. Not a directory: " + this);
289 | }
290 | }
291 |
292 | void guardRegisterWatchService(WatchService watchService) {
293 | Class extends WatchService> watchServiceClass = watchService.getClass();
294 | if (!GlusterWatchService.class.equals(watchServiceClass)) {
295 | throw new UnsupportedOperationException("GlusterPaths can only be watched by GlusterWatchServices. WatchService given: " + watchServiceClass);
296 | }
297 | }
298 |
299 | @Override
300 | public Iterator iterator() {
301 | List list = new ArrayList(parts.length);
302 | if (parts.length >= 1 && !parts[0].isEmpty()) {
303 | for (String p : parts) {
304 | list.add(new GlusterPath(fileSystem, p));
305 | }
306 | }
307 | return Collections.unmodifiableList(list).iterator();
308 | }
309 |
310 | @Override
311 | public int compareTo(Path path) {
312 | if (!getClass().equals(path.getClass())) {
313 | throw new ClassCastException();
314 | }
315 | if (!fileSystem.equals(path.getFileSystem())) {
316 | throw new IllegalArgumentException("Can not compare other path because it's on a different filesystem");
317 | }
318 | GlusterPath other = (GlusterPath) path;
319 | String[] otherParts = other.getParts();
320 | for (int i = 0; i < Math.min(parts.length, otherParts.length); i++) {
321 | int c = parts[i].compareTo(otherParts[i]);
322 | if (c != 0) {
323 | return c;
324 | }
325 | }
326 | return parts.length - otherParts.length;
327 | }
328 |
329 | public String toString() {
330 | return /*fileSystem.toString() +*/ getString();
331 | }
332 |
333 | public String getString() {
334 | if (null != pathString) {
335 | return pathString;
336 | } else {
337 | StringBuilder sb = new StringBuilder((absolute ? fileSystem.getSeparator() : ""));
338 | for (String p : parts) {
339 | sb.append(p).append(fileSystem.getSeparator());
340 | }
341 | sb.deleteCharAt(sb.length() - 1);
342 | return sb.toString();
343 | }
344 | }
345 | }
346 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/main/java/com/peircean/glusterfs/GlusterPathMatcher.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import java.nio.file.Path;
4 | import java.nio.file.PathMatcher;
5 | import java.util.regex.Pattern;
6 |
7 | class GlusterPathMatcher implements PathMatcher {
8 | Pattern pattern;
9 |
10 | public GlusterPathMatcher(Pattern pattern) {
11 | this.pattern = pattern;
12 | }
13 |
14 | @Override
15 | public boolean matches(Path path) {
16 | return pattern.matcher(path.toString()).matches();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/main/java/com/peircean/glusterfs/GlusterWatchEvent.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import lombok.Data;
4 |
5 | import java.nio.file.Path;
6 | import java.nio.file.StandardWatchEventKinds;
7 | import java.nio.file.WatchEvent;
8 |
9 | @Data
10 | public class GlusterWatchEvent implements WatchEvent {
11 | final private Path path;
12 | private Kind kind = StandardWatchEventKinds.ENTRY_CREATE;
13 | private int count = 0;
14 | private long lastModified;
15 |
16 | public Kind kind() {
17 | return kind;
18 | }
19 |
20 | @Override
21 | public int count() {
22 | return count;
23 | }
24 |
25 | @Override
26 | public Path context() {
27 | return path;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/main/java/com/peircean/glusterfs/GlusterWatchKey.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import lombok.Data;
4 | import lombok.EqualsAndHashCode;
5 | import lombok.NonNull;
6 |
7 | import java.io.IOException;
8 | import java.nio.file.*;
9 | import java.util.*;
10 |
11 | @Data
12 | @EqualsAndHashCode(of = "path")
13 | public class GlusterWatchKey implements WatchKey {
14 | private boolean valid = true;
15 | private boolean ready = true;
16 | Map events = new HashMap<>();
17 | final private GlusterPath path;
18 | @NonNull
19 | private WatchEvent.Kind[] kinds;
20 | private long lastPolled = (new Date()).getTime();
21 |
22 | @Override
23 | public boolean isValid() {
24 | return valid;
25 | }
26 |
27 | public boolean update() {
28 | DirectoryStream paths;
29 | try {
30 | paths = Files.newDirectoryStream(path);
31 | } catch (IOException e) {
32 | return false;
33 | }
34 | List files = new LinkedList<>();
35 | boolean newEvents = false;
36 | for (Path f : paths) {
37 | newEvents |= processExistingFile(files, f);
38 | }
39 | for (Path f : events.keySet()) {
40 | newEvents |= checkDeleted(files, f);
41 | }
42 | return newEvents;
43 | }
44 |
45 | boolean processExistingFile(List files, Path f) {
46 | if (Files.isDirectory(f)) {
47 | return false;
48 | }
49 | files.add(f);
50 |
51 | long lastModified;
52 | try {
53 | lastModified = Files.getLastModifiedTime(f).toMillis();
54 | } catch (IOException e) {
55 | return false;
56 | }
57 |
58 | GlusterWatchEvent event = events.get(f);
59 | if (null != event) {
60 | return checkModified(event, lastModified);
61 | } else {
62 | return checkCreated(f, lastModified);
63 | }
64 | }
65 |
66 | boolean checkDeleted(List files, Path f) {
67 | GlusterWatchEvent event = events.get(f);
68 | if (!files.contains(f) &&
69 | !StandardWatchEventKinds.ENTRY_DELETE.name().equals(event.kind().name())) {
70 | event.setLastModified((new Date()).getTime());
71 | event.setKind(StandardWatchEventKinds.ENTRY_DELETE);
72 | event.setCount(event.getCount() + 1);
73 | return true;
74 | }
75 | return false;
76 | }
77 |
78 | boolean checkCreated(Path f, long lastModified) {
79 | GlusterWatchEvent event = new GlusterWatchEvent(f.getFileName());
80 | event.setLastModified(lastModified);
81 | events.put(f, event);
82 | return (lastModified > lastPolled);
83 | }
84 |
85 | boolean checkModified(GlusterWatchEvent event, long lastModified) {
86 | if (lastModified > event.getLastModified()) {
87 | event.setLastModified(lastModified);
88 | if (event.kind().name().equals(StandardWatchEventKinds.ENTRY_DELETE.name())) {
89 | event.setKind(StandardWatchEventKinds.ENTRY_CREATE);
90 | event.setCount(0);
91 | } else {
92 | event.setKind(StandardWatchEventKinds.ENTRY_MODIFY);
93 | event.setCount(event.getCount() + 1);
94 | }
95 | return true;
96 | }
97 | return false;
98 | }
99 |
100 | boolean kindsContains(WatchEvent.Kind kind) {
101 | for (WatchEvent.Kind k : kinds) {
102 | if (k.name().equals(kind.name())) {
103 | return true;
104 | }
105 | }
106 | return false;
107 | }
108 |
109 | @Override
110 | synchronized public List> pollEvents() {
111 | if (!ready) {
112 | return new LinkedList<>();
113 | }
114 | ready = false;
115 | return findPendingEvents();
116 | }
117 |
118 | LinkedList> findPendingEvents() {
119 | long maxModifiedTime = lastPolled;
120 | LinkedList> pendingEvents = new LinkedList<>();
121 | for (Path p : events.keySet()) {
122 | long lastModified = queueEventIfPending(pendingEvents, p);
123 | maxModifiedTime = Math.max(maxModifiedTime, lastModified);
124 | }
125 | lastPolled = maxModifiedTime;
126 | return pendingEvents;
127 | }
128 |
129 | private long queueEventIfPending(LinkedList> pendingEvents, Path p) {
130 | GlusterWatchEvent e = events.get(p);
131 | long lastModified = e.getLastModified();
132 | if (lastModified > lastPolled && kindsContains(e.kind())) {
133 | pendingEvents.add(e);
134 | }
135 | return lastModified;
136 | }
137 |
138 | @Override
139 | synchronized public boolean reset() {
140 | if (!valid || ready) {
141 | return false;
142 | } else {
143 | ready = true;
144 | return true;
145 | }
146 | }
147 |
148 | @Override
149 | public void cancel() {
150 | valid = false;
151 | }
152 |
153 | @Override
154 | public Watchable watchable() {
155 | return path;
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/main/java/com/peircean/glusterfs/GlusterWatchService.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import lombok.Data;
4 |
5 | import java.io.IOException;
6 | import java.nio.file.ClosedWatchServiceException;
7 | import java.nio.file.WatchEvent;
8 | import java.nio.file.WatchKey;
9 | import java.nio.file.WatchService;
10 | import java.util.HashSet;
11 | import java.util.Iterator;
12 | import java.util.NoSuchElementException;
13 | import java.util.Set;
14 | import java.util.concurrent.TimeUnit;
15 |
16 | @Data
17 | public class GlusterWatchService implements WatchService {
18 | public static final int MILLIS_PER_SECOND = 1000;
19 | public static final int MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND;
20 | public static final int MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;
21 | public static final int MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR;
22 | public static long PERIOD = 100L;
23 |
24 | private Set paths = new HashSet<>();
25 | private Set pendingPaths = new HashSet<>();
26 | private boolean running = true;
27 |
28 | public WatchKey registerPath(GlusterPath path, WatchEvent.Kind... kinds) {
29 | if (!running) {
30 | throw new ClosedWatchServiceException();
31 | }
32 | for (GlusterWatchKey k : paths) {
33 | if (k.getPath().equals(path)) {
34 | k.setKinds(kinds);
35 | return k;
36 | }
37 | }
38 | GlusterWatchKey key = new GlusterWatchKey(path, kinds);
39 | paths.add(key);
40 | return key;
41 | }
42 |
43 | @Override
44 | public void close() throws IOException {
45 | if (running) {
46 | running = false;
47 | for (GlusterWatchKey k : paths) {
48 | k.cancel();
49 | }
50 | }
51 | }
52 |
53 | WatchKey popPending() {
54 | Iterator iterator = pendingPaths.iterator();
55 | try {
56 | GlusterWatchKey key = iterator.next();
57 | iterator.remove();
58 | return key;
59 | } catch (NoSuchElementException e) {
60 | return null;
61 | }
62 | }
63 |
64 | @Override
65 | public WatchKey poll() {
66 | if (!running) {
67 | throw new ClosedWatchServiceException();
68 | }
69 | WatchKey pending = popPending();
70 | if (null != pending) {
71 | return pending;
72 | }
73 | for (GlusterWatchKey k : paths) {
74 | if (k.isValid() && k.isReady() && k.update()) {
75 | pendingPaths.add(k);
76 | }
77 | }
78 | return popPending();
79 | }
80 |
81 | @Override
82 | public WatchKey poll(long timeout, TimeUnit unit) {
83 | long timeoutMillis = timeoutToMillis(timeout, unit);
84 | long loops = 0;
85 | while (running) {
86 | WatchKey key = poll();
87 | if (key != null) {
88 | return key;
89 | }
90 | if ((loops * PERIOD) > timeoutMillis) {
91 | return null;
92 | }
93 | loops++;
94 | try {
95 | Thread.sleep(PERIOD);
96 | } catch (InterruptedException e) {
97 | }
98 | }
99 | throw new ClosedWatchServiceException();
100 | }
101 |
102 | @Override
103 | public WatchKey take() {
104 | while (running) {
105 | WatchKey key = poll();
106 | if (key != null) {
107 | return key;
108 | }
109 | try {
110 | Thread.sleep(PERIOD);
111 | } catch (InterruptedException e) {
112 | }
113 | }
114 | throw new ClosedWatchServiceException();
115 | }
116 |
117 | long timeoutToMillis(long timeout, TimeUnit unit) {
118 | switch (unit) {
119 | case DAYS:
120 | return (timeout * MILLIS_PER_DAY);
121 | case HOURS:
122 | return (timeout * MILLIS_PER_HOUR);
123 | case MINUTES:
124 | return (timeout * MILLIS_PER_MINUTE);
125 | case SECONDS:
126 | return (timeout * MILLIS_PER_SECOND);
127 | case MILLISECONDS:
128 | return timeout;
129 | default: //MICROS & NANOS
130 | return -1;
131 | }
132 | }
133 |
134 | }
135 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/main/java/com/peircean/glusterfs/borrowed/GlobPattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | /*
20 | This file was borrowed for glusterfs-java-filesystem from Apache Hadoop
21 | by Louis Zuckerman. Original source URL:
22 | https://svn.apache.org/repos/asf/hadoop/common/tags/release-2.3.0-rc0/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/GlobPattern.java
23 | */
24 |
25 | // Changed package name. -LZ
26 | package com.peircean.glusterfs.borrowed;
27 |
28 | import java.util.regex.Pattern;
29 | import java.util.regex.PatternSyntaxException;
30 |
31 | /* Commented these lines. -LZ
32 | import org.apache.hadoop.classification.InterfaceAudience;
33 | import org.apache.hadoop.classification.InterfaceStability;
34 | @InterfaceAudience.Private
35 | @InterfaceStability.Evolving
36 |
37 | No other modifications made to the file. -LZ
38 | */
39 |
40 |
41 | /**
42 | * A class for POSIX glob pattern with brace expansions.
43 | */
44 | public class GlobPattern {
45 | private static final char BACKSLASH = '\\';
46 | private Pattern compiled;
47 | private boolean hasWildcard = false;
48 |
49 | /**
50 | * Construct the glob pattern object with a glob pattern string
51 | *
52 | * @param globPattern the glob pattern string
53 | */
54 | public GlobPattern(String globPattern) {
55 | set(globPattern);
56 | }
57 |
58 | /**
59 | * @return the compiled pattern
60 | */
61 | public Pattern compiled() {
62 | return compiled;
63 | }
64 |
65 | /**
66 | * Compile glob pattern string
67 | *
68 | * @param globPattern the glob pattern
69 | * @return the pattern object
70 | */
71 | public static Pattern compile(String globPattern) {
72 | return new GlobPattern(globPattern).compiled();
73 | }
74 |
75 | /**
76 | * Match input against the compiled glob pattern
77 | *
78 | * @param s input chars
79 | * @return true for successful matches
80 | */
81 | public boolean matches(CharSequence s) {
82 | return compiled.matcher(s).matches();
83 | }
84 |
85 | /**
86 | * Set and compile a glob pattern
87 | *
88 | * @param glob the glob pattern string
89 | */
90 | public void set(String glob) {
91 | StringBuilder regex = new StringBuilder();
92 | int setOpen = 0;
93 | int curlyOpen = 0;
94 | int len = glob.length();
95 | hasWildcard = false;
96 |
97 | for (int i = 0; i < len; i++) {
98 | char c = glob.charAt(i);
99 |
100 | switch (c) {
101 | case BACKSLASH:
102 | if (++i >= len) {
103 | error("Missing escaped character", glob, i);
104 | }
105 | regex.append(c).append(glob.charAt(i));
106 | continue;
107 | case '.':
108 | case '$':
109 | case '(':
110 | case ')':
111 | case '|':
112 | case '+':
113 | // escape regex special chars that are not glob special chars
114 | regex.append(BACKSLASH);
115 | break;
116 | case '*':
117 | regex.append('.');
118 | hasWildcard = true;
119 | break;
120 | case '?':
121 | regex.append('.');
122 | hasWildcard = true;
123 | continue;
124 | case '{': // start of a group
125 | regex.append("(?:"); // non-capturing
126 | curlyOpen++;
127 | hasWildcard = true;
128 | continue;
129 | case ',':
130 | regex.append(curlyOpen > 0 ? '|' : c);
131 | continue;
132 | case '}':
133 | if (curlyOpen > 0) {
134 | // end of a group
135 | curlyOpen--;
136 | regex.append(")");
137 | continue;
138 | }
139 | break;
140 | case '[':
141 | if (setOpen > 0) {
142 | error("Unclosed character class", glob, i);
143 | }
144 | setOpen++;
145 | hasWildcard = true;
146 | break;
147 | case '^': // ^ inside [...] can be unescaped
148 | if (setOpen == 0) {
149 | regex.append(BACKSLASH);
150 | }
151 | break;
152 | case '!': // [! needs to be translated to [^
153 | regex.append(setOpen > 0 && '[' == glob.charAt(i - 1) ? '^' : '!');
154 | continue;
155 | case ']':
156 | // Many set errors like [][] could not be easily detected here,
157 | // as []], []-] and [-] are all valid POSIX glob and java regex.
158 | // We'll just let the regex compiler do the real work.
159 | setOpen = 0;
160 | break;
161 | default:
162 | }
163 | regex.append(c);
164 | }
165 |
166 | if (setOpen > 0) {
167 | error("Unclosed character class", glob, len);
168 | }
169 | if (curlyOpen > 0) {
170 | error("Unclosed group", glob, len);
171 | }
172 | compiled = Pattern.compile(regex.toString());
173 | }
174 |
175 | /**
176 | * @return true if this is a wildcard pattern (with special chars)
177 | */
178 | public boolean hasWildcard() {
179 | return hasWildcard;
180 | }
181 |
182 | private static void error(String message, String pattern, int pos) {
183 | throw new PatternSyntaxException(message, pattern, pos);
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/main/resources/META-INF/services/java.nio.file.spi.FileSystemProvider:
--------------------------------------------------------------------------------
1 | com.peircean.glusterfs.GlusterFileSystemProvider
2 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/test/java/com/peircean/glusterfs/GlusterDirectoryIteratorTest.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import com.peircean.libgfapi_jni.internal.GLFS;
4 | import com.peircean.libgfapi_jni.internal.structs.dirent;
5 | import org.junit.Test;
6 | import org.junit.runner.RunWith;
7 | import org.mockito.Mock;
8 | import org.mockito.Mockito;
9 | import org.mockito.Spy;
10 | import org.powermock.api.mockito.PowerMockito;
11 | import org.powermock.core.classloader.annotations.PrepareForTest;
12 | import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor;
13 | import org.powermock.modules.junit4.PowerMockRunner;
14 |
15 | import java.nio.file.DirectoryStream;
16 | import java.nio.file.Path;
17 | import java.util.NoSuchElementException;
18 |
19 | import static org.junit.Assert.*;
20 | import static org.mockito.Mockito.*;
21 |
22 | @RunWith(PowerMockRunner.class)
23 | @PrepareForTest({GLFS.class, GlusterDirectoryIterator.class, dirent.class})
24 | @SuppressStaticInitializationFor("com.peircean.libgfapi_jni.internal.structs.dirent")
25 | public class GlusterDirectoryIteratorTest {
26 |
27 | @Mock
28 | private GlusterPath mockPath;
29 | @Mock
30 | private GlusterPath fakeResultPath;
31 | @Mock
32 | private GlusterFileSystem mockFileSystem;
33 | @Mock
34 | private GlusterDirectoryStream mockStream;
35 | @Mock
36 | private dirent mockCurrentDirent;
37 | @Mock
38 | private dirent mockNextDirent;
39 | @Mock
40 | private DirectoryStream.Filter super Path> mockFilter;
41 | @Spy
42 | private GlusterDirectoryIterator iterator = new GlusterDirectoryIterator();
43 | private long dirHandle = 12345l;
44 |
45 | @Test
46 | public void testHasNext_whenFilter() throws Exception {
47 | iterator.setFilter(mockFilter);
48 | iterator.setNextPath(fakeResultPath);
49 | when(mockFilter.accept(fakeResultPath)).thenReturn(false).thenReturn(true);
50 | mockNextDirent.d_ino = 1;
51 | iterator.setNext(mockNextDirent);
52 | doNothing().when(iterator).advance();
53 | assertTrue(iterator.hasNext());
54 | verify(iterator, times(2)).advance();
55 | verify(mockFilter, times(2)).accept(fakeResultPath);
56 | }
57 |
58 | @Test
59 | public void testHasNext_whenFilter_andNoNext() throws Exception {
60 | iterator.setFilter(mockFilter);
61 | iterator.setNextPath(fakeResultPath);
62 | when(mockFilter.accept(fakeResultPath)).thenReturn(false).thenReturn(true);
63 | mockNextDirent.d_ino = 0;
64 | iterator.setNext(mockNextDirent);
65 | doNothing().when(iterator).advance();
66 | assertFalse(iterator.hasNext());
67 | verify(iterator).advance();
68 | verify(mockFilter, never()).accept(fakeResultPath);
69 | }
70 |
71 | @Test
72 | public void testHasNext_whenNoFilter_andNoNext() throws Exception {
73 | mockNextDirent.d_ino = 0;
74 | iterator.setNext(mockNextDirent);
75 | doNothing().when(iterator).advance();
76 | assertFalse(iterator.hasNext());
77 | }
78 |
79 | @Test
80 | public void testHasNext_whenNoFilter() throws Exception {
81 | mockNextDirent.d_ino = 1;
82 | iterator.setNext(mockNextDirent);
83 | doNothing().when(iterator).advance();
84 | assertTrue(iterator.hasNext());
85 | }
86 |
87 | @Test
88 | public void testAdvance_whenNormalEntry() throws Exception {
89 | advanceHelper(0, true);
90 | }
91 |
92 | @Test
93 | public void testAdvance_skipSpecialEntryCurrent() throws Exception {
94 | advanceHelper(1, true);
95 | }
96 |
97 | @Test
98 | public void testAdvance_skipSpecialEntryParent() throws Exception {
99 | advanceHelper(1, false);
100 | }
101 |
102 | @Test
103 | public void testAdvance_skipSpecialEntryCurrentAndParent() throws Exception {
104 | advanceHelper(2, true);
105 | }
106 |
107 | /*
108 | * Type 0 = advancing on normal entry, so the boolean current value does not matter
109 | * Type 1 = advancing on either special entry "." or "..", differentiated by boolean current
110 | * Type 2 = advancing on both special entries "." and "..", so boolean current value does not matter
111 | */
112 | private void advanceHelper(int type, boolean current) throws Exception {
113 | doReturn(dirHandle).when(mockStream).getDirHandle();
114 | iterator.setStream(mockStream);
115 | switch (type) {
116 | case 1:
117 | PowerMockito.whenNew(dirent.class).withNoArguments().thenReturn(mockCurrentDirent, mockNextDirent,
118 | mockCurrentDirent, mockNextDirent);
119 | break;
120 | case 2:
121 | PowerMockito.whenNew(dirent.class).withNoArguments().thenReturn(mockCurrentDirent, mockNextDirent,
122 | mockCurrentDirent, mockNextDirent,
123 | mockCurrentDirent, mockNextDirent);
124 | break;
125 | default:
126 | PowerMockito.whenNew(dirent.class).withNoArguments().thenReturn(mockCurrentDirent, mockNextDirent);
127 | break;
128 | }
129 | long nextPtr = 4444l;
130 | PowerMockito.mockStatic(dirent.class);
131 | Mockito.when(dirent.malloc(dirent.SIZE_OF)).thenReturn(nextPtr);
132 |
133 | PowerMockito.doNothing().when(dirent.class);
134 | dirent.memmove(mockNextDirent, nextPtr, dirent.SIZE_OF);
135 | PowerMockito.doNothing().when(dirent.class);
136 | dirent.free(nextPtr);
137 |
138 | PowerMockito.mockStatic(GLFS.class);
139 | PowerMockito.when(GLFS.glfs_readdir_r(dirHandle, mockCurrentDirent, nextPtr)).thenReturn(0);
140 |
141 | Mockito.doReturn(mockPath).when(mockStream).getDir();
142 | String stringPath = "foo";
143 | switch (type) {
144 | case 1:
145 | if (current) {
146 | when(mockCurrentDirent.getName()).thenReturn(".", stringPath);
147 | } else {
148 | when(mockCurrentDirent.getName()).thenReturn("..", stringPath);
149 | }
150 | break;
151 | case 2:
152 | when(mockCurrentDirent.getName()).thenReturn(".", "..", stringPath);
153 | break;
154 | default:
155 | when(mockCurrentDirent.getName()).thenReturn(stringPath);
156 | break;
157 | }
158 | when(mockPath.resolve(any(String.class))).thenReturn(fakeResultPath);
159 |
160 | iterator.advance();
161 |
162 | assertEquals(fakeResultPath, iterator.getNextPath());
163 |
164 | verify(mockPath).resolve(stringPath);
165 | switch (type) {
166 | case 1:
167 | verify(mockCurrentDirent, times(2)).getName();
168 | if (current) {
169 | verify(mockPath).resolve(".");
170 | } else {
171 | verify(mockPath).resolve("..");
172 | }
173 | verify(mockStream, times(2)).getDir();
174 | verify(mockStream, times(2)).getDirHandle();
175 |
176 | PowerMockito.verifyNew(dirent.class, times(4)).withNoArguments();
177 | PowerMockito.verifyStatic(times(2));
178 | dirent.memmove(mockNextDirent, nextPtr, dirent.SIZE_OF);
179 | PowerMockito.verifyStatic(times(2));
180 | dirent.free(nextPtr);
181 | break;
182 | case 2:
183 | verify(mockCurrentDirent, times(3)).getName();
184 | verify(mockPath).resolve(".");
185 | verify(mockPath).resolve("..");
186 | verify(mockStream, times(3)).getDir();
187 | verify(mockStream, times(3)).getDirHandle();
188 |
189 | PowerMockito.verifyNew(dirent.class, times(6)).withNoArguments();
190 | PowerMockito.verifyStatic(times(3));
191 | dirent.memmove(mockNextDirent, nextPtr, dirent.SIZE_OF);
192 | PowerMockito.verifyStatic(times(3));
193 | dirent.free(nextPtr);
194 | break;
195 | default:
196 | verify(mockCurrentDirent).getName();
197 | verify(mockStream).getDir();
198 | verify(mockStream).getDirHandle();
199 |
200 | PowerMockito.verifyNew(dirent.class, times(2)).withNoArguments();
201 | PowerMockito.verifyStatic();
202 | dirent.memmove(mockNextDirent, nextPtr, dirent.SIZE_OF);
203 | PowerMockito.verifyStatic();
204 | dirent.free(nextPtr);
205 | break;
206 | }
207 | }
208 |
209 | @Test(expected = NoSuchElementException.class)
210 | public void testNext_whenNoNext() {
211 | iterator.next();
212 | }
213 |
214 | @Test
215 | public void testNext() {
216 | iterator.setNextPath(fakeResultPath);
217 | GlusterPath path = iterator.next();
218 | assertEquals(fakeResultPath, path);
219 | }
220 |
221 | @Test(expected = UnsupportedOperationException.class)
222 | public void testRemove() {
223 | iterator.remove();
224 | }
225 | }
226 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/test/java/com/peircean/glusterfs/GlusterDirectoryStreamTest.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import com.peircean.libgfapi_jni.internal.GLFS;
4 | import org.junit.Test;
5 | import org.junit.runner.RunWith;
6 | import org.mockito.Mock;
7 | import org.mockito.Mockito;
8 | import org.mockito.Spy;
9 | import org.powermock.core.classloader.annotations.PrepareForTest;
10 | import org.powermock.modules.junit4.PowerMockRunner;
11 |
12 | import java.io.IOException;
13 | import java.nio.file.DirectoryStream;
14 | import java.nio.file.Path;
15 | import java.util.Iterator;
16 |
17 | import static org.junit.Assert.assertEquals;
18 | import static org.mockito.Mockito.doReturn;
19 | import static org.mockito.Mockito.verify;
20 | import static org.powermock.api.mockito.PowerMockito.*;
21 |
22 | @RunWith(PowerMockRunner.class)
23 | @PrepareForTest({GlusterDirectoryStream.class, GLFS.class})
24 | public class GlusterDirectoryStreamTest {
25 | private long dirHandle = 12345l;
26 |
27 | private long fsHandle = 56789l;
28 |
29 | @Mock
30 | private GlusterDirectoryIterator mockIterator;
31 |
32 | @Mock
33 | private GlusterPath mockPath;
34 |
35 | @Mock
36 | private GlusterFileSystem mockFileSystem;
37 |
38 | @Mock
39 | private DirectoryStream.Filter super Path> mockFilter;
40 |
41 | @Spy
42 | private GlusterDirectoryStream stream = new GlusterDirectoryStream();
43 |
44 | @Test(expected = IllegalStateException.class)
45 | public void testOpenDirectory_whenAlreadyOpen() {
46 | stream.setDirHandle(1);
47 | stream.open(mockPath);
48 | }
49 |
50 | @Test
51 | public void testOpenDirectory() {
52 | String fakePath = "/foo/baz";
53 | doReturn(mockFileSystem).when(mockPath).getFileSystem();
54 | doReturn(fsHandle).when(mockFileSystem).getVolptr();
55 | doReturn(fakePath).when(mockPath).getString();
56 |
57 | mockStatic(GLFS.class);
58 | when(GLFS.glfs_opendir(fsHandle, fakePath)).thenReturn(dirHandle);
59 |
60 | stream.open(mockPath);
61 |
62 | assertEquals(dirHandle, stream.getDirHandle());
63 | assertEquals(false, stream.isClosed());
64 | assertEquals(mockPath, stream.getDir());
65 | verify(mockPath).getFileSystem();
66 | verify(mockFileSystem).getVolptr();
67 | verify(mockPath).getString();
68 | verifyStatic();
69 | GLFS.glfs_opendir(fsHandle, fakePath);
70 | }
71 |
72 | @Test(expected = IllegalStateException.class)
73 | public void testIterator_whenAlreadyIterating() {
74 | stream.setIterator(mockIterator);
75 | stream.iterator();
76 | }
77 |
78 | @Test(expected = IllegalStateException.class)
79 | public void testIterator_whenClosed() {
80 | stream.setClosed(true);
81 | stream.iterator();
82 | }
83 |
84 | @Test
85 | public void testIterator() throws Exception {
86 | stream.setClosed(false);
87 | stream.setFilter(mockFilter);
88 | whenNew(GlusterDirectoryIterator.class).
89 | withNoArguments().thenReturn(mockIterator);
90 | stream.setDirHandle(dirHandle);
91 | Iterator iterator = stream.iterator();
92 | verifyNew(GlusterDirectoryIterator.class).withNoArguments();
93 | assertEquals(mockIterator, iterator);
94 | assertEquals(mockIterator, stream.getIterator());
95 | verify(mockIterator).setStream(stream);
96 | verify(mockIterator).setFilter(mockFilter);
97 | }
98 |
99 | @Test
100 | public void testClose_whenAlreadyClosed() throws IOException {
101 | stream.setDirHandle(dirHandle);
102 | stream.setClosed(true);
103 | mockStatic(GLFS.class);
104 |
105 | stream.close();
106 |
107 | verifyStatic(Mockito.never());
108 | GLFS.glfs_close(dirHandle);
109 | }
110 |
111 | @Test
112 | public void testClose() throws IOException {
113 | stream.setDirHandle(dirHandle);
114 | mockStatic(GLFS.class);
115 | Mockito.when(GLFS.glfs_close(dirHandle)).thenReturn(0);
116 |
117 | stream.close();
118 |
119 | verifyStatic();
120 | GLFS.glfs_close(dirHandle);
121 | }
122 |
123 | }
124 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/test/java/com/peircean/glusterfs/GlusterFileAttributesTest.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import junit.framework.TestCase;
4 | import com.peircean.libgfapi_jni.internal.structs.stat;
5 | import org.junit.Test;
6 |
7 | import java.nio.file.attribute.FileAttribute;
8 | import java.nio.file.attribute.FileTime;
9 | import java.nio.file.attribute.PosixFilePermission;
10 | import java.nio.file.attribute.PosixFilePermissions;
11 | import java.util.Set;
12 |
13 | public class GlusterFileAttributesTest extends TestCase {
14 |
15 | public static final int MODE = 0100777;
16 | public static final int UID = 1000;
17 | public static final int GID = 1001;
18 | public static final long SIZE = 1234l;
19 | public static final long ATIME = 1373464796l;
20 | public static final long CTIME = 1373464797l;
21 | public static final long MTIME = 1373464798l;
22 | public static final long INODE = 4452352l;
23 | private GlusterFileAttributes attrib = new GlusterFileAttributes(MODE, UID, GID, SIZE, ATIME, CTIME, MTIME, INODE);
24 |
25 | @Test
26 | public void testOwner() {
27 | assertEquals(String.valueOf(UID), attrib.owner().getName());
28 | }
29 |
30 | @Test
31 | public void testGroup() {
32 | assertEquals(String.valueOf(GID), attrib.group().getName());
33 | }
34 |
35 | @Test
36 | public void testModified() {
37 | assertEquals(FileTime.fromMillis(MTIME * 1000), attrib.lastModifiedTime());
38 | }
39 |
40 | @Test
41 | public void testCreated() {
42 | assertEquals(FileTime.fromMillis(CTIME * 1000), attrib.creationTime());
43 | }
44 |
45 | @Test
46 | public void testAccessed() {
47 | assertEquals(FileTime.fromMillis(ATIME * 1000), attrib.lastAccessTime());
48 | }
49 |
50 | @Test
51 | public void testPermissions() {
52 | Set expected = PosixFilePermissions.fromString("rwxrwxrwx");
53 | Set permissions = attrib.permissions();
54 | assertEquals(expected, permissions);
55 | }
56 |
57 | @Test
58 | public void testParseAttributes() {
59 | Set posixFilePermissions = PosixFilePermissions.fromString("rwxrwxrwx");
60 | FileAttribute> attrs = PosixFilePermissions.asFileAttribute(posixFilePermissions);
61 | int mode = GlusterFileAttributes.parseAttrs(attrs);
62 | assertEquals(0777, mode);
63 | }
64 |
65 |
66 | @Test
67 | public void testIsRegular() {
68 | assertTrue(attrib.isRegularFile());
69 | }
70 |
71 | @Test
72 | public void testIsSymbolic() {
73 | attrib = new GlusterFileAttributes(0120777, UID, GID, SIZE, ATIME, CTIME, MTIME, INODE);
74 | assertTrue(attrib.isSymbolicLink());
75 | }
76 |
77 | @Test
78 | public void testIsDirectory() {
79 | attrib = new GlusterFileAttributes(0040777, UID, GID, SIZE, ATIME, CTIME, MTIME, INODE);
80 | assertTrue(attrib.isDirectory());
81 | }
82 |
83 | @Test
84 | public void testIsOther() {
85 | attrib = new GlusterFileAttributes(0000777, UID, GID, SIZE, ATIME, CTIME, MTIME, INODE);
86 | assertTrue(attrib.isOther());
87 | }
88 |
89 | @Test
90 | public void testSize() {
91 | assertEquals(SIZE, attrib.size());
92 | }
93 |
94 | @Test
95 | public void testFileKey() {
96 | assertEquals(INODE, attrib.fileKey());
97 | }
98 |
99 | @Test
100 | public void testFromStat() {
101 | stat stat = new stat();
102 | stat.st_size = SIZE;
103 | stat.st_gid = GID;
104 | stat.st_uid = UID;
105 | stat.st_mode = MODE;
106 | stat.st_ino = INODE;
107 | stat.atime = ATIME;
108 | stat.mtime = MTIME;
109 | stat.ctime = CTIME;
110 |
111 | GlusterFileAttributes attr = GlusterFileAttributes.fromStat(stat);
112 |
113 | assertEquals(stat.st_size, attr.getSize());
114 | assertEquals(stat.st_uid, attr.getUid());
115 | assertEquals(stat.st_gid, attr.getGid());
116 | assertEquals(stat.st_mode, attr.getMode());
117 | assertEquals(stat.st_ino, attr.getInode());
118 | assertEquals(stat.atime, attr.getAtime());
119 | assertEquals(stat.mtime, attr.getMtime());
120 | assertEquals(stat.ctime, attr.getCtime());
121 |
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/test/java/com/peircean/glusterfs/GlusterFileChannelTest.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import com.peircean.libgfapi_jni.internal.GLFS;
4 | import com.peircean.libgfapi_jni.internal.GlusterOpenOption;
5 | import com.peircean.libgfapi_jni.internal.structs.stat;
6 | import junit.framework.TestCase;
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 | import org.mockito.Mock;
10 | import org.mockito.Mockito;
11 | import org.mockito.Spy;
12 | import org.powermock.api.mockito.PowerMockito;
13 | import org.powermock.core.classloader.annotations.PrepareForTest;
14 | import org.powermock.modules.junit4.PowerMockRunner;
15 |
16 | import java.io.IOException;
17 | import java.net.URI;
18 | import java.net.URISyntaxException;
19 | import java.nio.ByteBuffer;
20 | import java.nio.channels.ClosedChannelException;
21 | import java.nio.channels.FileChannel;
22 | import java.nio.channels.NonReadableChannelException;
23 | import java.nio.channels.NonWritableChannelException;
24 | import java.nio.file.FileAlreadyExistsException;
25 | import java.nio.file.OpenOption;
26 | import java.nio.file.StandardOpenOption;
27 | import java.nio.file.attribute.FileAttribute;
28 | import java.nio.file.attribute.PosixFilePermission;
29 | import java.nio.file.attribute.PosixFilePermissions;
30 | import java.util.Arrays;
31 | import java.util.HashSet;
32 | import java.util.Set;
33 |
34 | import static org.mockito.Mockito.*;
35 | import static org.powermock.api.mockito.PowerMockito.mockStatic;
36 | import static org.powermock.api.mockito.PowerMockito.verifyStatic;
37 |
38 | /**
39 | * @author Louis Zuckerman
40 | */
41 | @RunWith(PowerMockRunner.class)
42 | @PrepareForTest({GLFS.class, GlusterFileChannel.class, GlusterFileAttributes.class})
43 | public class GlusterFileChannelTest extends TestCase {
44 |
45 | @Mock
46 | private GlusterPath mockPath;
47 | @Mock
48 | private GlusterFileSystem mockFileSystem;
49 | @Mock
50 | private ByteBuffer mockBuffer;
51 | @Spy
52 | private GlusterFileChannel channel = new GlusterFileChannel();
53 |
54 | @Test(expected = IllegalStateException.class)
55 | public void testNewFileChannel_whenNotAbsolutePath() throws IOException, URISyntaxException {
56 | doReturn(false).when(mockPath).isAbsolute();
57 | initTestHelper(null, false, false);
58 | }
59 |
60 | @Test
61 | public void testNewFileChannel_whenCreate() throws IOException, URISyntaxException {
62 | doReturn(true).when(mockPath).isAbsolute();
63 | initTestHelper(StandardOpenOption.CREATE, true, false);
64 | }
65 |
66 | @Test
67 | public void testNewFileChannel_whenCreateNew() throws IOException, URISyntaxException {
68 | doReturn(true).when(mockPath).isAbsolute();
69 | initTestHelper(StandardOpenOption.CREATE_NEW, true, false);
70 | }
71 |
72 | @Test(expected = FileAlreadyExistsException.class)
73 | public void testNewFileChannel_whenCreateNew_andFileAlreadyExists() throws IOException, URISyntaxException {
74 | doReturn(true).when(mockPath).isAbsolute();
75 | initTestHelper(StandardOpenOption.CREATE_NEW, false, false);
76 | }
77 |
78 | @Test
79 | public void testNewFileChannel_whenNotCreating() throws IOException, URISyntaxException {
80 | doReturn(true).when(mockPath).isAbsolute();
81 | initTestHelper(null, false, true);
82 | }
83 |
84 | @Test(expected = IOException.class)
85 | public void testNewFileChannel_whenFailing() throws IOException, URISyntaxException {
86 | doReturn(true).when(mockPath).isAbsolute();
87 | initTestHelper(null, false, false);
88 | }
89 |
90 | private void initTestHelper(StandardOpenOption option, boolean created, boolean opened) throws IOException, URISyntaxException {
91 | Set options = new HashSet();
92 | options.add(StandardOpenOption.WRITE);
93 | if (null != option) {
94 | options.add(option);
95 | }
96 |
97 | Set posixFilePermissions = PosixFilePermissions.fromString("rw-rw-rw-");
98 | FileAttribute> attrs = PosixFilePermissions.asFileAttribute(posixFilePermissions);
99 |
100 | int mode = 0666;
101 | int flags = GlusterOpenOption.WRITE().create().getValue();
102 | long volptr = 1234l;
103 | String path = "/foo/bar";
104 | long createptr = created ? 4321l : 0;
105 | long openptr = opened ? 4321l : 0;
106 | URI pathUri = new URI("gluster://server:volume" + path);
107 | doReturn(volptr).when(mockFileSystem).getVolptr();
108 | doReturn(pathUri).when(mockPath).toUri();
109 | doReturn(flags).when(channel).parseOptions(options);
110 | mockStatic(GlusterFileAttributes.class);
111 | when(GlusterFileAttributes.parseAttrs(attrs)).thenReturn(mode);
112 |
113 | mockStatic(GLFS.class);
114 | if (null != option) {
115 | when(GLFS.glfs_creat(volptr, path, flags, mode)).thenReturn(createptr);
116 | } else {
117 | when(GLFS.glfs_open(volptr, path, flags)).thenReturn(openptr);
118 | }
119 |
120 | channel.init(mockFileSystem, mockPath, options, attrs);
121 |
122 | assertEquals(mockFileSystem, channel.getFileSystem());
123 | assertEquals(mockPath, channel.getPath());
124 | assertEquals(options, channel.getOptions());
125 | assertEquals(null, channel.getAttrs());
126 |
127 | verify(mockFileSystem).getVolptr();
128 | verify(mockPath).toUri();
129 | verify(channel).parseOptions(options);
130 | verifyStatic();
131 | GlusterFileAttributes.parseAttrs(attrs);
132 |
133 | if (null != option) {
134 | verifyStatic();
135 | GLFS.glfs_creat(volptr, path, flags, mode);
136 | } else {
137 | verifyStatic();
138 | GLFS.glfs_open(volptr, path, flags);
139 | }
140 | }
141 |
142 | @Test
143 | public void testParseOptions() {
144 | Set options = new HashSet();
145 | options.add(StandardOpenOption.APPEND);
146 | options.add(StandardOpenOption.WRITE);
147 |
148 | int result = channel.parseOptions(options);
149 |
150 | assertEquals(GlusterOpenOption.O_RDWR | GlusterOpenOption.O_APPEND, result);
151 | }
152 |
153 | @Test
154 | public void testRead1Arg() throws IOException {
155 | doNothing().when(channel).guardClosed();
156 | long fileptr = 1234l;
157 | channel.setFileptr(fileptr);
158 |
159 | byte[] bytes = new byte[]{'a', 'b', 'c'};
160 | long bufferLength = bytes.length;
161 | long offset = 4;
162 | channel.setPosition(offset);
163 |
164 | mockStatic(GLFS.class);
165 | when(GLFS.glfs_read(fileptr, bytes, bufferLength, 0)).thenReturn(bufferLength);
166 |
167 | doReturn(bytes).when(mockBuffer).array();
168 | doReturn(mockBuffer).when(mockBuffer).position((int) bufferLength);
169 |
170 | int read = channel.read(mockBuffer);
171 |
172 | assertEquals(bufferLength, read);
173 |
174 | verify(channel).guardClosed();
175 | verify(mockBuffer).array();
176 | verify(mockBuffer).position((int) bufferLength);
177 | assertEquals(bufferLength + offset, channel.getPosition());
178 |
179 | verifyStatic();
180 | GLFS.glfs_read(fileptr, bytes, bufferLength, 0);
181 | }
182 |
183 | @Test(expected = IOException.class)
184 | public void testRead1Arg_whenReadFails() throws IOException {
185 | doNothing().when(channel).guardClosed();
186 | long fileptr = 1234l;
187 | channel.setFileptr(fileptr);
188 |
189 | byte[] bytes = new byte[]{'a', 'b', 'c'};
190 | long bufferLength = bytes.length;
191 | long offset = 4;
192 | channel.setPosition(offset);
193 |
194 | mockStatic(GLFS.class);
195 | when(GLFS.glfs_read(fileptr, bytes, bufferLength, 0)).thenReturn(-1L);
196 |
197 | doReturn(bytes).when(mockBuffer).array();
198 |
199 | channel.read(mockBuffer);
200 | }
201 |
202 | @Test
203 | public void testRead3Arg() throws IOException {
204 | doNothing().when(channel).guardClosed();
205 | Set options = new HashSet<>();
206 | options.add(StandardOpenOption.READ);
207 | channel.setOptions(options);
208 | ByteBuffer[] buffers = new ByteBuffer[2];
209 | buffers[0] = mockBuffer;
210 | buffers[1] = mockBuffer;
211 | channel.setPosition(0);
212 | int offset = 0;
213 | int length = 2;
214 | doReturn(10L).when(channel).readHelper(buffers, offset, length);
215 | long read = channel.read(buffers, offset, length);
216 |
217 | verify(channel).readHelper(buffers, offset, length);
218 | verify(channel).guardClosed();
219 | assertEquals(channel.position(), read);
220 | }
221 |
222 | @Test(expected = ClosedChannelException.class)
223 | public void testRead3Arg_whenClosed() throws IOException {
224 | channel.setClosed(true);
225 | ByteBuffer[] buffers = new ByteBuffer[2];
226 | buffers[0] = mockBuffer;
227 | buffers[1] = mockBuffer;
228 | int offset = 0;
229 | int length = 2;
230 | channel.read(buffers, offset, length);
231 | }
232 |
233 | @Test(expected = IndexOutOfBoundsException.class)
234 | public void testRead3Arg_whenLengthTooSmall() throws IOException {
235 | read3ArgLengthOffsetTestHelper(true, false);
236 | }
237 |
238 | @Test(expected = IndexOutOfBoundsException.class)
239 | public void testRead3Arg_whenLengthTooBig() throws IOException {
240 | read3ArgLengthOffsetTestHelper(true, true);
241 | }
242 |
243 | @Test(expected = IndexOutOfBoundsException.class)
244 | public void testRead3Arg_whenOffsetTooSmall() throws IOException {
245 | read3ArgLengthOffsetTestHelper(false, false);
246 | }
247 |
248 | @Test(expected = IndexOutOfBoundsException.class)
249 | public void testRead3Arg_whenOffsetTooBig() throws IOException {
250 | read3ArgLengthOffsetTestHelper(false, true);
251 | }
252 |
253 | private void read3ArgLengthOffsetTestHelper(boolean testingLength, boolean testingTooBig) throws IOException {
254 | doNothing().when(channel).guardClosed();
255 | ByteBuffer[] buffers = new ByteBuffer[2];
256 | buffers[0] = mockBuffer;
257 | buffers[1] = mockBuffer;
258 | int offset = 0;
259 | int length = 2;
260 |
261 | if (testingLength) {
262 | if (testingTooBig) {
263 | length = 3;
264 | } else {
265 | length = -1;
266 | }
267 | } else {
268 | if (testingTooBig) {
269 | offset = 3;
270 | } else {
271 | offset = 1;
272 | }
273 | }
274 |
275 | channel.read(buffers, offset, length);
276 | }
277 |
278 | @Test(expected = NonReadableChannelException.class)
279 | public void testRead3Arg_whenNonReadableChannel() throws IOException {
280 | doNothing().when(channel).guardClosed();
281 | ByteBuffer[] buffers = new ByteBuffer[2];
282 | buffers[0] = mockBuffer;
283 | buffers[1] = mockBuffer;
284 | int offset = 0;
285 | int length = 2;
286 | channel.read(buffers, offset, length);
287 | }
288 |
289 | @Test
290 | public void testReadHelper() throws IOException {
291 | long fileptr = 1234L;
292 | channel.setFileptr(fileptr);
293 |
294 | ByteBuffer[] buffers = new ByteBuffer[2];
295 | buffers[0] = mockBuffer;
296 | buffers[1] = mockBuffer;
297 | int offset = 0;
298 | int length = 2;
299 |
300 | byte[] bytes = new byte[]{'h', 'e', 'l', 'l', 'o'};
301 | doReturn(bytes).when(mockBuffer).array();
302 |
303 | when(mockBuffer.remaining()).thenReturn(5, 0, 5, 0);
304 |
305 | mockStatic(GLFS.class);
306 | when(GLFS.glfs_read(fileptr, bytes, 5, 0)).thenReturn(5L);
307 | doReturn(mockBuffer).when(mockBuffer).position(5);
308 |
309 | channel.readHelper(buffers, offset, length);
310 |
311 | verify(mockBuffer, times(2)).position(5);
312 | verifyStatic(times(2));
313 | GLFS.glfs_read(fileptr, bytes, 5, 0);
314 | verify(mockBuffer, times(4)).remaining();
315 | verify(mockBuffer, times(2)).array();
316 | }
317 |
318 | @Test(expected = IOException.class)
319 | public void testReadHelper_whenReadFails() throws IOException {
320 | long fileptr = 1234L;
321 | channel.setFileptr(fileptr);
322 |
323 | ByteBuffer[] buffers = new ByteBuffer[2];
324 | buffers[0] = mockBuffer;
325 | buffers[1] = mockBuffer;
326 | int offset = 0;
327 | int length = 2;
328 |
329 | byte[] bytes = new byte[]{'h', 'e', 'l', 'l', 'o'};
330 | doReturn(bytes).when(mockBuffer).array();
331 |
332 | when(mockBuffer.remaining()).thenReturn(5, 0, 5, 0);
333 |
334 | mockStatic(GLFS.class);
335 | when(GLFS.glfs_read(fileptr, bytes, 5, 0)).thenReturn(-1L);
336 |
337 | channel.readHelper(buffers, offset, length);
338 | }
339 |
340 | @Test
341 | public void testReadHelper_whenEndOfStreamAndTotalReadZero() throws IOException {
342 | long fileptr = 1234L;
343 | channel.setFileptr(fileptr);
344 |
345 | ByteBuffer[] buffers = new ByteBuffer[2];
346 | buffers[0] = mockBuffer;
347 | buffers[1] = mockBuffer;
348 | int offset = 0;
349 | int length = 2;
350 |
351 | byte[] bytes = new byte[]{'h', 'e', 'l', 'l', 'o'};
352 | doReturn(bytes).when(mockBuffer).array();
353 |
354 | when(mockBuffer.remaining()).thenReturn(5, 0, 5, 0);
355 |
356 | mockStatic(GLFS.class);
357 | when(GLFS.glfs_read(fileptr, bytes, 5, 0)).thenReturn(0L);
358 | doReturn(mockBuffer).when(mockBuffer).position(0);
359 |
360 | long ret = channel.readHelper(buffers, offset, length);
361 |
362 | assertEquals(ret, -1);
363 | verify(mockBuffer).position(0);
364 | verifyStatic();
365 | GLFS.glfs_read(fileptr, bytes, 5, 0);
366 | verify(mockBuffer).remaining();
367 | verify(mockBuffer).array();
368 | }
369 |
370 | @Test
371 | public void testRead2Arg() throws IOException {
372 | long position = 5L;
373 | long fileptr = 1234L;
374 | long defaultPosition = 0L;
375 | channel.setFileptr(fileptr);
376 | channel.setPosition(defaultPosition);
377 |
378 | doNothing().when(channel).guardClosed();
379 |
380 | Set options = new HashSet<>();
381 | options.add(StandardOpenOption.READ);
382 | channel.setOptions(options);
383 |
384 | doReturn(10L).when(channel).size();
385 |
386 | mockStatic(GLFS.class);
387 | when(GLFS.glfs_lseek(fileptr, position, 0)).thenReturn(0);
388 |
389 | byte[] bytes = new byte[]{'h', 'e', 'l', 'l', 'o'};
390 | doReturn(bytes).when(mockBuffer).array();
391 |
392 | long expectedRet = 7L;
393 | when(GLFS.glfs_read(fileptr, bytes, bytes.length, 0)).thenReturn(expectedRet);
394 |
395 | when(GLFS.glfs_lseek(fileptr, defaultPosition, 0)).thenReturn(0);
396 |
397 | long ret = channel.read(mockBuffer, position);
398 |
399 | assertEquals(ret, expectedRet);
400 | verifyStatic();
401 | GLFS.glfs_lseek(fileptr, defaultPosition, 0);
402 | verifyStatic();
403 | GLFS.glfs_read(fileptr, bytes, bytes.length, 0);
404 | verify(mockBuffer).array();
405 | verifyStatic();
406 | GLFS.glfs_lseek(fileptr, position, 0);
407 | verify(channel).size();
408 | verify(channel).guardClosed();
409 | }
410 |
411 | @Test(expected = ClosedChannelException.class)
412 | public void testRead2Arg_whenClosed() throws IOException {
413 | long position = 5L;
414 | channel.setClosed(true);
415 | channel.read(mockBuffer, position);
416 | }
417 |
418 | @Test(expected = IllegalArgumentException.class)
419 | public void testRead2Arg_whenPositionNegative() throws IOException {
420 | long position = -1L;
421 |
422 | doNothing().when(channel).guardClosed();
423 |
424 | channel.read(mockBuffer, position);
425 | }
426 |
427 | @Test(expected = NonReadableChannelException.class)
428 | public void testRead2Arg_whenNonReadableChannel() throws IOException {
429 | long position = 5L;
430 |
431 | doNothing().when(channel).guardClosed();
432 |
433 | channel.read(mockBuffer, position);
434 | }
435 |
436 | @Test
437 | public void testRead2Arg_whenPositionTooBig() throws IOException {
438 | long position = 5L;
439 |
440 | doNothing().when(channel).guardClosed();
441 |
442 | Set options = new HashSet<>();
443 | options.add(StandardOpenOption.READ);
444 | channel.setOptions(options);
445 |
446 | doReturn(4L).when(channel).size();
447 |
448 | long expectedRet = -1L;
449 |
450 | long ret = channel.read(mockBuffer, position);
451 |
452 | assertEquals(ret, expectedRet);
453 | verify(channel).size();
454 | verify(channel).guardClosed();
455 | }
456 |
457 | @Test(expected = IOException.class)
458 | public void testRead2Arg_whenFirstSeekFails() throws IOException {
459 | long position = 5L;
460 | long fileptr = 1234L;
461 | channel.setFileptr(fileptr);
462 |
463 | doNothing().when(channel).guardClosed();
464 |
465 | Set options = new HashSet<>();
466 | options.add(StandardOpenOption.READ);
467 | channel.setOptions(options);
468 |
469 | doReturn(10L).when(channel).size();
470 |
471 | mockStatic(GLFS.class);
472 | when(GLFS.glfs_lseek(fileptr, position, 0)).thenReturn(-1);
473 |
474 | channel.read(mockBuffer, position);
475 |
476 | verifyStatic();
477 | GLFS.glfs_lseek(fileptr, position, 0);
478 | verify(channel).size();
479 | verify(channel).guardClosed();
480 | }
481 |
482 | @Test(expected = IOException.class)
483 | public void testRead2Arg_whenReadFails() throws IOException {
484 | long position = 5L;
485 | long fileptr = 1234L;
486 | long defaultPosition = 0L;
487 | channel.setFileptr(fileptr);
488 | channel.setPosition(defaultPosition);
489 |
490 | doNothing().when(channel).guardClosed();
491 |
492 | Set options = new HashSet<>();
493 | options.add(StandardOpenOption.READ);
494 | channel.setOptions(options);
495 |
496 | doReturn(10L).when(channel).size();
497 |
498 | mockStatic(GLFS.class);
499 | when(GLFS.glfs_lseek(fileptr, position, 0)).thenReturn(0);
500 |
501 | byte[] bytes = new byte[]{'h', 'e', 'l', 'l', 'o'};
502 | doReturn(bytes).when(mockBuffer).array();
503 |
504 | long expectedRet = -1;
505 | when(GLFS.glfs_read(fileptr, bytes, bytes.length, 0)).thenReturn(expectedRet);
506 |
507 | channel.read(mockBuffer, position);
508 |
509 | verifyStatic();
510 | GLFS.glfs_read(fileptr, bytes, bytes.length, 0);
511 | verify(mockBuffer).array();
512 | verifyStatic();
513 | GLFS.glfs_lseek(fileptr, position, 0);
514 | verify(channel).size();
515 | verify(channel).guardClosed();
516 | }
517 |
518 | @Test(expected = IOException.class)
519 | public void testRead2Arg_whenSecondSeekFails() throws IOException {
520 | long position = 5L;
521 | long fileptr = 1234L;
522 | long defaultPosition = 0L;
523 | channel.setFileptr(fileptr);
524 | channel.setPosition(defaultPosition);
525 |
526 | doNothing().when(channel).guardClosed();
527 |
528 | Set options = new HashSet<>();
529 | options.add(StandardOpenOption.READ);
530 | channel.setOptions(options);
531 |
532 | doReturn(10L).when(channel).size();
533 |
534 | mockStatic(GLFS.class);
535 | when(GLFS.glfs_lseek(fileptr, position, 0)).thenReturn(0);
536 |
537 | byte[] bytes = new byte[]{'h', 'e', 'l', 'l', 'o'};
538 | doReturn(bytes).when(mockBuffer).array();
539 |
540 | long expectedRet = 7L;
541 | when(GLFS.glfs_read(fileptr, bytes, bytes.length, 0)).thenReturn(expectedRet);
542 |
543 | when(GLFS.glfs_lseek(fileptr, defaultPosition, 0)).thenReturn(-1);
544 |
545 | channel.read(mockBuffer, position);
546 |
547 | verifyStatic();
548 | GLFS.glfs_lseek(fileptr, defaultPosition, 0);
549 | verifyStatic();
550 | GLFS.glfs_read(fileptr, bytes, bytes.length, 0);
551 | verify(mockBuffer).array();
552 | verifyStatic();
553 | GLFS.glfs_lseek(fileptr, position, 0);
554 | verify(channel).size();
555 | verify(channel).guardClosed();
556 | }
557 |
558 | @Test
559 | public void testWrite1Arg() throws IOException {
560 | doNothing().when(channel).guardClosed();
561 | long fileptr = 1234L;
562 | channel.setFileptr(fileptr);
563 |
564 | byte[] bytes = new byte[]{'a', 'b'};
565 | int bufferLength = bytes.length;
566 |
567 | mockStatic(GLFS.class);
568 | when(GLFS.glfs_write(fileptr, bytes, bufferLength, 0)).thenReturn(bufferLength);
569 |
570 | doReturn(bytes).when(mockBuffer).array();
571 | doReturn(null).when(mockBuffer).position(bufferLength);
572 |
573 | int written = channel.write(mockBuffer);
574 |
575 | assertEquals(bufferLength, written);
576 |
577 | verify(channel).guardClosed();
578 | verify(mockBuffer).array();
579 | verify(mockBuffer).position(bufferLength);
580 |
581 | verifyStatic();
582 | GLFS.glfs_write(fileptr, bytes, bufferLength, 0);
583 | }
584 |
585 | @Test
586 | public void testWrite3Arg() throws IOException {
587 | doNothing().when(channel).guardClosed();
588 | long fileptr = 1234L;
589 | channel.setFileptr(fileptr);
590 | Set extends OpenOption> mockOptions = Mockito.mock(Set.class);
591 | channel.setOptions(mockOptions);
592 | doReturn(true).when(mockOptions).contains(StandardOpenOption.WRITE);
593 |
594 | byte[] bytes1 = new byte[10];
595 | byte[] bytes2 = new byte[10];
596 | ByteBuffer buffer1 = ByteBuffer.wrap(bytes1);
597 | ByteBuffer buffer2 = ByteBuffer.wrap(bytes2);
598 | ByteBuffer[] buffers = new ByteBuffer[]{buffer1, buffer2};
599 | int length = 2;
600 | int offset = 0;
601 |
602 | mockStatic(GLFS.class);
603 | when(GLFS.glfs_write(fileptr, bytes1, 10, 0)).thenReturn(10);
604 | when(GLFS.glfs_write(fileptr, bytes2, 10, 0)).thenReturn(10);
605 |
606 | long ret = channel.write(buffers, offset, length);
607 |
608 | assertEquals(ret, 20);
609 |
610 | verifyStatic(times(2));
611 | GLFS.glfs_write(fileptr, bytes1, 10, 0);
612 |
613 | verify(mockOptions).contains(StandardOpenOption.WRITE);
614 | verify(channel).guardClosed();
615 | }
616 |
617 | @Test(expected = NonWritableChannelException.class)
618 | public void testWrite3Arg_whenChannelNotOpenedForWrite() throws IOException {
619 | doNothing().when(channel).guardClosed();
620 | long fileptr = 1234L;
621 | channel.setFileptr(fileptr);
622 | Set extends OpenOption> mockOptions = Mockito.mock(Set.class);
623 | channel.setOptions(mockOptions);
624 | doReturn(false).when(mockOptions).contains(StandardOpenOption.WRITE);
625 |
626 | int length = 2;
627 | int offset = 0;
628 | ByteBuffer buffer1 = Mockito.mock(ByteBuffer.class);
629 | ByteBuffer buffer2 = Mockito.mock(ByteBuffer.class);
630 | ByteBuffer[] buffers = new ByteBuffer[]{buffer1, buffer2};
631 |
632 | channel.write(buffers, offset, length);
633 | }
634 |
635 | @Test(expected = IndexOutOfBoundsException.class)
636 | public void testWrite3Arg_whenLengthNegative() throws IOException {
637 | testWrite3Arg_helper(true, false);
638 | }
639 |
640 | @Test(expected = IndexOutOfBoundsException.class)
641 | public void testWrite3Arg_whenLengthTooBig() throws IOException {
642 | testWrite3Arg_helper(true, true);
643 | }
644 |
645 | @Test(expected = IndexOutOfBoundsException.class)
646 | public void testWrite3Arg_whenOffsetNegative() throws IOException {
647 | testWrite3Arg_helper(false, false);
648 | }
649 |
650 | @Test(expected = IndexOutOfBoundsException.class)
651 | public void testWrite3Arg_whenOffsetTooBig() throws IOException {
652 | testWrite3Arg_helper(false, true);
653 | }
654 |
655 | private void testWrite3Arg_helper(boolean testingLength, boolean testingTooBig) throws IOException {
656 | doNothing().when(channel).guardClosed();
657 |
658 | int length;
659 | int offset;
660 | if (testingLength) {
661 | offset = 0;
662 | if (testingTooBig) {
663 | length = 3;
664 | } else {
665 | length = -1;
666 | }
667 | } else {
668 | length = 2;
669 | if (testingTooBig) {
670 | offset = 3;
671 | } else {
672 | offset = -1;
673 | }
674 | }
675 | ByteBuffer buffer1 = Mockito.mock(ByteBuffer.class);
676 | ByteBuffer buffer2 = Mockito.mock(ByteBuffer.class);
677 | ByteBuffer[] buffers = new ByteBuffer[]{buffer1, buffer2};
678 |
679 | channel.write(buffers, offset, length);
680 | }
681 |
682 | @Test(expected = ClosedChannelException.class)
683 | public void testWrite3Arg_whenClosedChannel() throws IOException {
684 | channel.setClosed(true);
685 |
686 | int length = 2;
687 | int offset = 0;
688 | ByteBuffer buffer1 = Mockito.mock(ByteBuffer.class);
689 | ByteBuffer buffer2 = Mockito.mock(ByteBuffer.class);
690 | ByteBuffer[] buffers = new ByteBuffer[]{buffer1, buffer2};
691 |
692 | channel.write(buffers, offset, length);
693 | }
694 |
695 | @Test
696 | public void testWrite2Arg_positionLessThanSize() throws IOException {
697 | testWrite2Arg_helper(false);
698 | }
699 |
700 | @Test
701 | public void testWrite2Arg_positionGreaterThanSize() throws IOException {
702 | testWrite2Arg_helper(true);
703 | }
704 |
705 | private void testWrite2Arg_helper(boolean testingPositionSize) throws IOException {
706 | doNothing().when(channel).guardClosed();
707 | long fileptr = 1234L;
708 | channel.setFileptr(fileptr);
709 | Set extends OpenOption> mockOptions = Mockito.mock(Set.class);
710 | channel.setOptions(mockOptions);
711 | doReturn(true).when(mockOptions).contains(StandardOpenOption.WRITE);
712 | channel.setPosition(0L);
713 | doReturn(3L).when(channel).size();
714 |
715 | byte[] bytes = new byte[10];
716 | ByteBuffer buffer = ByteBuffer.wrap(bytes);
717 | long position = 2L;
718 |
719 | if (testingPositionSize) {
720 | position = 3L;
721 | mockStatic(Arrays.class);
722 | when(Arrays.copyOf(bytes, bytes.length)).thenReturn(bytes);
723 | mockStatic(ByteBuffer.class);
724 | when(ByteBuffer.wrap(bytes)).thenReturn(buffer);
725 | }
726 |
727 | mockStatic(GLFS.class);
728 | when(GLFS.glfs_write(fileptr, bytes, 10, 0)).thenReturn(10);
729 | when(GLFS.glfs_lseek(fileptr, position, 0)).thenReturn(0);
730 | when(GLFS.glfs_lseek(fileptr, 0L, 0)).thenReturn(0);
731 |
732 | int ret = channel.write(buffer, position);
733 |
734 | assertEquals(ret, 10);
735 |
736 | verifyStatic();
737 | GLFS.glfs_lseek(fileptr, 0L, 0);
738 | verifyStatic();
739 | GLFS.glfs_lseek(fileptr, position, 0);
740 | verifyStatic();
741 | GLFS.glfs_write(fileptr, bytes, 10, 0);
742 |
743 | if (testingPositionSize) {
744 | verifyStatic();
745 | ByteBuffer.wrap(bytes);
746 | verifyStatic();
747 | Arrays.copyOf(bytes, bytes.length);
748 | }
749 |
750 | verify(channel, times(testingPositionSize ? 2 : 1)).size();
751 | verify(mockOptions).contains(StandardOpenOption.WRITE);
752 | verify(channel).guardClosed();
753 | }
754 |
755 | @Test(expected = IOException.class)
756 | public void testWrite2Arg_firstSeekFails() throws IOException {
757 | doNothing().when(channel).guardClosed();
758 | long fileptr = 1234L;
759 | channel.setFileptr(fileptr);
760 | Set extends OpenOption> mockOptions = Mockito.mock(Set.class);
761 | channel.setOptions(mockOptions);
762 | doReturn(true).when(mockOptions).contains(StandardOpenOption.WRITE);
763 | channel.setPosition(0L);
764 | doReturn(3L).when(channel).size();
765 |
766 | byte[] bytes = new byte[10];
767 | ByteBuffer buffer = ByteBuffer.wrap(bytes);
768 | long position = 2L;
769 |
770 | mockStatic(GLFS.class);
771 | when(GLFS.glfs_write(fileptr, bytes, 10, 0)).thenReturn(10);
772 | when(GLFS.glfs_lseek(fileptr, position, 0)).thenReturn(0);
773 | when(GLFS.glfs_lseek(fileptr, 0L, 0)).thenReturn(-1);
774 |
775 | channel.write(buffer, position);
776 | }
777 |
778 | @Test(expected = IOException.class)
779 | public void testWrite2Arg_secondSeekFails() throws IOException {
780 | doNothing().when(channel).guardClosed();
781 | long fileptr = 1234L;
782 | channel.setFileptr(fileptr);
783 | Set extends OpenOption> mockOptions = Mockito.mock(Set.class);
784 | channel.setOptions(mockOptions);
785 | doReturn(true).when(mockOptions).contains(StandardOpenOption.WRITE);
786 | channel.setPosition(0L);
787 | doReturn(3L).when(channel).size();
788 |
789 | byte[] bytes = new byte[10];
790 | ByteBuffer buffer = ByteBuffer.wrap(bytes);
791 | long position = 2L;
792 |
793 | mockStatic(GLFS.class);
794 | when(GLFS.glfs_write(fileptr, bytes, 10, 0)).thenReturn(10);
795 | when(GLFS.glfs_lseek(fileptr, position, 0)).thenReturn(-1);
796 |
797 | channel.write(buffer, position);
798 | }
799 |
800 | @Test(expected = NonWritableChannelException.class)
801 | public void testWrite2Arg_whenChannelNonWritable() throws IOException {
802 | doNothing().when(channel).guardClosed();
803 | Set extends OpenOption> mockOptions = Mockito.mock(Set.class);
804 | channel.setOptions(mockOptions);
805 | doReturn(false).when(mockOptions).contains(StandardOpenOption.WRITE);
806 |
807 | ByteBuffer buffer = Mockito.mock(ByteBuffer.class);
808 | long position = 2L;
809 |
810 | channel.write(buffer, position);
811 | }
812 |
813 | @Test(expected = IllegalArgumentException.class)
814 | public void testWrite2Arg_positionInvalid() throws IOException {
815 | doNothing().when(channel).guardClosed();
816 |
817 | ByteBuffer buffer = Mockito.mock(ByteBuffer.class);
818 | long position = -1L;
819 |
820 | channel.write(buffer, position);
821 | }
822 |
823 | @Test(expected = ClosedChannelException.class)
824 | public void testWrite2Arg_whenChannelClosed() throws IOException {
825 | channel.setClosed(true);
826 |
827 | ByteBuffer buffer = Mockito.mock(ByteBuffer.class);
828 | long position = 0L;
829 |
830 | channel.write(buffer, position);
831 | }
832 |
833 | @Test
834 | public void testGuardClosed_whenNotClosed() throws ClosedChannelException {
835 | channel.setClosed(false);
836 | channel.guardClosed();
837 | }
838 |
839 | @Test(expected = ClosedChannelException.class)
840 | public void testGuardClosed_whenClosed() throws ClosedChannelException {
841 | channel.setClosed(true);
842 | channel.guardClosed();
843 | }
844 |
845 | @Test
846 | public void testGetPosition() throws IOException {
847 | doNothing().when(channel).guardClosed();
848 | long position = 12345l;
849 | channel.setPosition(position);
850 | long returnedPosition = channel.position();
851 | verify(channel).guardClosed();
852 | assertEquals(position, returnedPosition);
853 | }
854 |
855 | @Test(expected = IllegalArgumentException.class)
856 | public void testSetPosition_whenNegative() throws IOException {
857 | long position = -1l;
858 | channel.position(position);
859 | }
860 |
861 | @Test
862 | public void testSetPosition() throws IOException {
863 | doNothing().when(channel).guardClosed();
864 | long fileptr = 123l;
865 | channel.setFileptr(fileptr);
866 | long position = 12345l;
867 |
868 | mockStatic(GLFS.class);
869 | when(GLFS.glfs_lseek(fileptr, position, 0)).thenReturn(0);
870 | FileChannel returnedChannel = channel.position(position);
871 |
872 | verify(channel).guardClosed();
873 | assertEquals(channel, returnedChannel);
874 | assertEquals(position, channel.getPosition());
875 |
876 | verifyStatic();
877 | GLFS.glfs_lseek(fileptr, position, 0);
878 | }
879 |
880 | @Test(expected = IOException.class)
881 | public void testForce_whenFailing() throws IOException {
882 | long fileptr = 1234l;
883 | channel.setFileptr(fileptr);
884 |
885 | mockStatic(GLFS.class);
886 | when(GLFS.glfs_fsync(fileptr)).thenReturn(-1);
887 |
888 | channel.force(true);
889 | }
890 |
891 | @Test
892 | public void testForce() throws IOException {
893 | doNothing().when(channel).guardClosed();
894 | long fileptr = 1234l;
895 | channel.setFileptr(fileptr);
896 |
897 | mockStatic(GLFS.class);
898 | when(GLFS.glfs_fsync(fileptr)).thenReturn(0);
899 |
900 | channel.force(true);
901 | verify(channel).guardClosed();
902 | verifyStatic();
903 | GLFS.glfs_fsync(fileptr);
904 | }
905 |
906 | @Test(expected = IOException.class)
907 | public void testImplCloseChannel_whenFailing() throws IOException {
908 | long fileptr = 1234l;
909 | channel.setFileptr(fileptr);
910 |
911 | mockStatic(GLFS.class);
912 | when(GLFS.glfs_close(fileptr)).thenReturn(1);
913 |
914 | channel.implCloseChannel();
915 | }
916 |
917 | @Test
918 | public void testImplCloseChannel_whenAlreadyClosed() throws IOException {
919 | channel.setClosed(true);
920 | long fileptr = 1234l;
921 | channel.setFileptr(fileptr);
922 |
923 | mockStatic(GLFS.class);
924 | when(GLFS.glfs_close(fileptr)).thenReturn(0);
925 |
926 | channel.implCloseChannel();
927 |
928 | assertTrue(channel.isClosed());
929 |
930 | verifyStatic(never());
931 | GLFS.glfs_close(fileptr);
932 | }
933 |
934 | @Test
935 | public void testImplCloseChannel() throws IOException {
936 | long fileptr = 1234l;
937 | channel.setFileptr(fileptr);
938 |
939 | mockStatic(GLFS.class);
940 | when(GLFS.glfs_close(fileptr)).thenReturn(0);
941 |
942 | channel.implCloseChannel();
943 |
944 | assertTrue(channel.isClosed());
945 |
946 | verifyStatic();
947 | GLFS.glfs_close(fileptr);
948 | }
949 |
950 | @Test
951 | public void testSize() throws Exception {
952 | long fileptr = 1234l;
953 | channel.setFileptr(fileptr);
954 |
955 | long actualSize = 321l;
956 | stat stat = new stat();
957 | stat.st_size = actualSize;
958 |
959 | PowerMockito.whenNew(stat.class).withNoArguments().thenReturn(stat);
960 |
961 | mockStatic(GLFS.class);
962 | when(GLFS.glfs_fstat(fileptr, stat)).thenReturn(0);
963 |
964 | long size = channel.size();
965 |
966 | assertEquals(actualSize, size);
967 |
968 | verifyStatic();
969 | GLFS.glfs_fstat(fileptr, stat);
970 | }
971 |
972 | @Test(expected = IOException.class)
973 | public void testSize_whenFailing() throws Exception {
974 | long fileptr = 1234l;
975 | channel.setFileptr(fileptr);
976 |
977 | long actualSize = 321l;
978 | stat stat = new stat();
979 | stat.st_size = actualSize;
980 |
981 | PowerMockito.whenNew(stat.class).withNoArguments().thenReturn(stat);
982 |
983 | mockStatic(GLFS.class);
984 | when(GLFS.glfs_fstat(fileptr, stat)).thenReturn(-1);
985 |
986 | long size = channel.size();
987 | }
988 |
989 | }
990 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/test/java/com/peircean/glusterfs/GlusterFileStoreTest.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import junit.framework.TestCase;
4 | import org.junit.Before;
5 | import org.junit.Test;
6 | import org.junit.runner.RunWith;
7 | import org.mockito.Mock;
8 | import org.mockito.runners.MockitoJUnitRunner;
9 |
10 | import java.io.IOException;
11 |
12 | import static org.mockito.Mockito.doReturn;
13 | import static org.mockito.Mockito.verify;
14 |
15 | /**
16 | * @author Louis Zuckerman
17 | */
18 | @RunWith(MockitoJUnitRunner.class)
19 | public class GlusterFileStoreTest extends TestCase {
20 |
21 | @Mock
22 | private GlusterFileSystem mockFileSystem;
23 | @Mock
24 | private GlusterFileSystemProvider mockProvider;
25 | private GlusterFileStore fileStore;
26 |
27 | @Before
28 | public void setUp() {
29 | doReturn(mockProvider).when(mockFileSystem).provider();
30 | fileStore = new GlusterFileStore(mockFileSystem);
31 | }
32 |
33 | @Test
34 | public void testName() {
35 | String volname = "testvol";
36 | doReturn(volname).when(mockFileSystem).getVolname();
37 | assertEquals(volname, fileStore.name());
38 | }
39 |
40 | @Test
41 | public void testType() {
42 | assertEquals("glusterfs", fileStore.type());
43 | }
44 |
45 | @Test
46 | public void testIsReadOnly() {
47 | assertFalse(fileStore.isReadOnly());
48 | }
49 |
50 | @Test
51 | public void testGetTotalSpace() throws IOException {
52 | long volptr = 4321l;
53 | long space = 1234l;
54 | doReturn(volptr).when(mockFileSystem).getVolptr();
55 | doReturn(space).when(mockProvider).getTotalSpace(volptr);
56 | long totalSpace = fileStore.getTotalSpace();
57 | verify(mockProvider).getTotalSpace(volptr);
58 | verify(mockFileSystem).getVolptr();
59 | assertEquals(space, totalSpace);
60 | }
61 |
62 | @Test
63 | public void testGetUsableSpace() throws IOException {
64 | long volptr = 4321l;
65 | long space = 1234l;
66 | doReturn(volptr).when(mockFileSystem).getVolptr();
67 | doReturn(space).when(mockProvider).getUsableSpace(volptr);
68 | long usableSpace = fileStore.getUsableSpace();
69 | verify(mockProvider).getUsableSpace(volptr);
70 | verify(mockFileSystem).getVolptr();
71 | assertEquals(space, usableSpace);
72 | }
73 |
74 | @Test
75 | public void testGetUnallocatedSpace() throws IOException {
76 | long volptr = 4321l;
77 | long space = 1234l;
78 | doReturn(volptr).when(mockFileSystem).getVolptr();
79 | doReturn(space).when(mockProvider).getUnallocatedSpace(volptr);
80 | long unallocatedSpace = fileStore.getUnallocatedSpace();
81 | verify(mockProvider).getUnallocatedSpace(volptr);
82 | verify(mockFileSystem).getVolptr();
83 | assertEquals(space, unallocatedSpace);
84 | }
85 |
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/test/java/com/peircean/glusterfs/GlusterFileSystemTest.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import com.peircean.glusterfs.borrowed.GlobPattern;
4 | import junit.framework.TestCase;
5 | import org.junit.Before;
6 | import org.junit.Test;
7 | import org.junit.runner.RunWith;
8 | import org.mockito.Mock;
9 | import org.powermock.api.mockito.PowerMockito;
10 | import org.powermock.core.classloader.annotations.PrepareForTest;
11 | import org.powermock.modules.junit4.PowerMockRunner;
12 |
13 | import java.io.IOException;
14 | import java.nio.file.FileStore;
15 | import java.nio.file.Path;
16 | import java.nio.file.PathMatcher;
17 | import java.util.Iterator;
18 | import java.util.regex.Matcher;
19 | import java.util.regex.Pattern;
20 | import java.util.regex.PatternSyntaxException;
21 |
22 | import static org.mockito.Mockito.doReturn;
23 | import static org.mockito.Mockito.*;
24 | import static org.mockito.Mockito.when;
25 | import static org.powermock.api.mockito.PowerMockito.*;
26 |
27 | /**
28 | * @author Louis Zuckerman
29 | */
30 | @RunWith(PowerMockRunner.class)
31 | @PrepareForTest({Pattern.class, GlobPattern.class, GlusterFileSystem.class})
32 | public class GlusterFileSystemTest extends TestCase {
33 | public static final long VOLPTR = 1234l;
34 | public static final String VOLNAME = "testvol";
35 | public static final String HOST = "123.45.67.89";
36 | @Mock
37 | private GlusterFileSystemProvider mockFileSystemProvider;
38 | @Mock
39 | private GlusterPath mockPath;
40 | @Mock
41 | private GlusterPathMatcher mockMatcher;
42 |
43 | private GlusterFileSystem fileSystem;
44 |
45 | @Before
46 | public void setUp() {
47 | fileSystem = new GlusterFileSystem(mockFileSystemProvider, HOST, VOLNAME, VOLPTR);
48 | }
49 |
50 | @Test
51 | public void testProvider() {
52 | assertEquals(mockFileSystemProvider, fileSystem.provider());
53 | }
54 |
55 | @Test(expected = IOException.class)
56 | public void testClose_whenFailing() throws IOException {
57 | doReturn(11).when(mockFileSystemProvider).close(VOLPTR);
58 | fileSystem.close();
59 | }
60 |
61 | @Test
62 | public void testClose() throws IOException {
63 | doReturn(0).when(mockFileSystemProvider).close(VOLPTR);
64 | fileSystem.close();
65 | verify(mockFileSystemProvider).close(VOLPTR);
66 | assertEquals(-1, fileSystem.getVolptr());
67 | }
68 |
69 | @Test
70 | public void testIsOpen_whenOpen() {
71 | assertEquals(true, fileSystem.isOpen());
72 | }
73 |
74 | @Test
75 | public void testIsOpen_whenClosed() {
76 | fileSystem.setVolptr(-1);
77 | assertEquals(false, fileSystem.isOpen());
78 | }
79 |
80 | @Test
81 | public void testIsReadOnly() {
82 | assertFalse(fileSystem.isReadOnly());
83 | }
84 |
85 | @Test
86 | public void testGetSeparator() {
87 | assertEquals("/", fileSystem.getSeparator());
88 | }
89 |
90 | @Test
91 | public void testGetRootDirectories() {
92 | Iterable pi = fileSystem.getRootDirectories();
93 | Iterator iterator = pi.iterator();
94 | Path path = new GlusterPath(fileSystem, "/");
95 | assertEquals(path, iterator.next());
96 | assertFalse(iterator.hasNext());
97 | }
98 |
99 | @Test
100 | public void testGetFileStores() {
101 | GlusterFileStore correctStore = new GlusterFileStore(fileSystem);
102 | Iterable stores = fileSystem.getFileStores();
103 | Iterator iterator = stores.iterator();
104 | assertEquals(correctStore, iterator.next());
105 | assertFalse(iterator.hasNext());
106 | }
107 |
108 | @Test
109 | public void testGetPath() {
110 | Path correctPath = new GlusterPath(fileSystem, "/foo/bar/baz");
111 | Path returnedPath = fileSystem.getPath("/foo", "bar", "baz");
112 | assertEquals(correctPath, returnedPath);
113 | }
114 |
115 | @Test
116 | public void testToString() {
117 | doReturn("gluster").when(mockFileSystemProvider).getScheme();
118 | String string = "gluster://" + HOST + ":" + VOLNAME;
119 | assertEquals(string, fileSystem.toString());
120 | verify(mockFileSystemProvider).getScheme();
121 | }
122 |
123 | @Test(expected = IllegalArgumentException.class)
124 | public void testGetPathMatcher_whenBadInput() {
125 | fileSystem.getPathMatcher("foo");
126 | }
127 |
128 | @Test(expected = UnsupportedOperationException.class)
129 | public void testGetPathMatcher_whenBadSyntax() {
130 | fileSystem.getPathMatcher("foo:bar");
131 | }
132 |
133 | @Test(expected = PatternSyntaxException.class)
134 | public void testGetPathMatcher_whenBadExpression() {
135 | fileSystem.getPathMatcher("regex:[");
136 | }
137 |
138 | @Test
139 | public void testGetPathMatcher_whenGlob() throws Exception {
140 | pathMatcherHelper(true);
141 | }
142 |
143 | @Test
144 | public void testGetPathMatcher_whenRegex() throws Exception {
145 | pathMatcherHelper(false);
146 | }
147 |
148 | void pathMatcherHelper(boolean glob) throws Exception {
149 | PowerMockito.mockStatic(GlobPattern.class);
150 | Pattern pattern = PowerMockito.mock(Pattern.class);
151 | Matcher matcher = PowerMockito.mock(Matcher.class);
152 |
153 | String globPattern = "someglob";
154 | if (glob) {
155 | mockStatic(GlobPattern.class);
156 | when(GlobPattern.compile(globPattern)).thenReturn(pattern);
157 | } else {
158 | mockStatic(Pattern.class);
159 | when(Pattern.compile(globPattern)).thenReturn(pattern);
160 | }
161 |
162 | when(pattern.matcher(globPattern)).thenReturn(matcher);
163 | PowerMockito.whenNew(GlusterPathMatcher.class).withArguments(pattern).thenReturn(mockMatcher);
164 |
165 | String syntax;
166 | if (glob) {
167 | syntax = "glob";
168 | } else {
169 | syntax = "regex";
170 | }
171 | PathMatcher pathMatcher = fileSystem.getPathMatcher(syntax + ":" + globPattern);
172 |
173 | assertEquals(mockMatcher, pathMatcher);
174 |
175 | verifyNew(GlusterPathMatcher.class).withArguments(pattern);
176 |
177 | if (glob) {
178 | verifyStatic();
179 | GlobPattern.compile(globPattern);
180 | } else {
181 | verifyStatic();
182 | Pattern.compile(globPattern);
183 | }
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/test/java/com/peircean/glusterfs/GlusterPathMatcherTest.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import com.peircean.glusterfs.borrowed.GlobPattern;
4 | import org.junit.Test;
5 | import org.junit.runner.RunWith;
6 | import org.mockito.Mock;
7 | import org.powermock.api.mockito.PowerMockito;
8 | import org.powermock.core.classloader.annotations.PrepareForTest;
9 | import org.powermock.modules.junit4.PowerMockRunner;
10 |
11 | import java.net.URISyntaxException;
12 | import java.util.regex.Matcher;
13 | import java.util.regex.Pattern;
14 |
15 | import static org.junit.Assert.assertEquals;
16 | import static org.mockito.Mockito.doReturn;
17 | import static org.mockito.Mockito.when;
18 |
19 | @RunWith(PowerMockRunner.class)
20 | @PrepareForTest({Pattern.class, Matcher.class, GlusterPathMatcher.class, GlobPattern.class})
21 | public class GlusterPathMatcherTest {
22 | @Mock
23 | private GlusterPath mockPath;
24 |
25 | @Test
26 | public void testPathMatcherMatches_whenTrue() throws URISyntaxException {
27 | matchesHelper(true);
28 | }
29 |
30 | @Test
31 | public void testPathMatcherMatches_whenFalse() throws URISyntaxException {
32 | matchesHelper(false);
33 | }
34 |
35 | void matchesHelper(boolean result) throws URISyntaxException {
36 | Pattern pattern = PowerMockito.mock(Pattern.class);
37 | Matcher matcher = PowerMockito.mock(Matcher.class);
38 | String foo = "/foo";
39 |
40 | doReturn(foo).when(mockPath).toString();
41 |
42 | when(pattern.matcher(foo)).thenReturn(matcher);
43 | when(matcher.matches()).thenReturn(result);
44 |
45 | GlusterPathMatcher pathMatcher = new GlusterPathMatcher(pattern);
46 |
47 | boolean matches = pathMatcher.matches(mockPath);
48 |
49 | assertEquals(result, matches);
50 |
51 | // verify doesn't work with toString or PowerMock objects
52 | // verify(mockPath).toString();
53 |
54 | // verify(pattern).matcher(foo);
55 | // verify(matcher).matches();
56 |
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/test/java/com/peircean/glusterfs/GlusterPathPowerMockTest.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.mockito.Mock;
6 | import org.powermock.api.mockito.PowerMockito;
7 | import org.powermock.core.classloader.annotations.PrepareForTest;
8 | import org.powermock.modules.junit4.PowerMockRunner;
9 |
10 | import java.nio.file.Files;
11 | import java.nio.file.NotDirectoryException;
12 |
13 | import static org.mockito.Mockito.when;
14 |
15 | @RunWith(PowerMockRunner.class)
16 | @PrepareForTest({GlusterPath.class, Files.class})
17 | public class GlusterPathPowerMockTest {
18 | @Mock
19 | private GlusterFileSystem mockFileSystem;
20 |
21 | @Test(expected = NotDirectoryException.class)
22 | public void testGuardRegisterWatchDirectory_whenNotDirectory() throws NotDirectoryException {
23 | GlusterPath path = new GlusterPath(mockFileSystem, new String[]{"/foo"}, false);
24 |
25 | PowerMockito.mockStatic(Files.class);
26 | when(Files.isDirectory(path)).thenReturn(false);
27 |
28 | path.guardRegisterWatchDirectory();
29 | }
30 |
31 | @Test
32 | public void testGuardRegisterWatchDirectory() throws NotDirectoryException {
33 | GlusterPath path = new GlusterPath(mockFileSystem, new String[]{"/foo"}, false);
34 |
35 | PowerMockito.mockStatic(Files.class);
36 | when(Files.isDirectory(path)).thenReturn(true);
37 |
38 | path.guardRegisterWatchDirectory();
39 |
40 | PowerMockito.verifyStatic();
41 | Files.isDirectory(path);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/test/java/com/peircean/glusterfs/GlusterPathTest.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import junit.framework.TestCase;
4 | import org.junit.Before;
5 | import org.junit.Test;
6 | import org.junit.runner.RunWith;
7 | import org.mockito.Mock;
8 | import org.mockito.runners.MockitoJUnitRunner;
9 |
10 | import java.io.IOException;
11 | import java.net.URI;
12 | import java.net.URISyntaxException;
13 | import java.nio.file.*;
14 | import java.util.Iterator;
15 | import java.util.LinkedList;
16 | import java.util.List;
17 |
18 | import static org.mockito.Mockito.*;
19 |
20 | /**
21 | * @author Louis Zuckerman
22 | */
23 | @RunWith(MockitoJUnitRunner.class)
24 | public class GlusterPathTest extends TestCase {
25 | @Mock
26 | private GlusterFileSystem mockFileSystem;
27 | @Mock
28 | private GlusterPath mockGlusterPath;
29 |
30 | @Before
31 | public void setUp() {
32 | doReturn("/").when(mockFileSystem).getSeparator();
33 | }
34 |
35 | @Test
36 | public void testConstruct() {
37 | GlusterPath p = new GlusterPath(mockFileSystem, "/foo/bar");
38 | assertEquals(2, p.getParts().length);
39 |
40 | p = new GlusterPath(mockFileSystem, "foo/bar");
41 | assertEquals(2, p.getParts().length);
42 |
43 | p = new GlusterPath(mockFileSystem, "foo/bar/");
44 | assertEquals(2, p.getParts().length);
45 |
46 | p = new GlusterPath(mockFileSystem, "/foo/bar/");
47 | assertEquals(2, p.getParts().length);
48 | }
49 |
50 | @Test(expected = IllegalArgumentException.class)
51 | public void testConstruct_noFileSystem() {
52 | Path p = new GlusterPath(null, "");
53 | }
54 |
55 | // @Test(expected = InvalidPathException.class)
56 | // public void testConstruct_emptyPath() {
57 | // Path p = new GlusterPath(mockFileSystem, "");
58 | // }
59 |
60 | @Test(expected = InvalidPathException.class)
61 | public void testConstruct_nullPath() {
62 | Path p = new GlusterPath(mockFileSystem, null);
63 | }
64 |
65 | @Test
66 | public void testConstruct_internal() {
67 | String[] parts = {"a", "b"};
68 | GlusterPath p = new GlusterPath(mockFileSystem, parts, true);
69 | assertEquals(parts, p.getParts());
70 | assertEquals(mockFileSystem, p.getFileSystem());
71 | }
72 |
73 | @Test
74 | public void testIsAbsolute() {
75 | Path p = new GlusterPath(mockFileSystem, "foo/bar");
76 | assertFalse(p.isAbsolute());
77 |
78 | p = new GlusterPath(mockFileSystem, "/foo/bar");
79 | assertTrue(p.isAbsolute());
80 | }
81 |
82 | @Test
83 | public void testGetRoot_absolute() {
84 | List paths = new LinkedList();
85 | GlusterPath root = new GlusterPath(mockFileSystem, "/");
86 | paths.add(root);
87 | doReturn(paths).when(mockFileSystem).getRootDirectories();
88 |
89 | Path p = new GlusterPath(mockFileSystem, "/foo/bar");
90 | Path returned = p.getRoot();
91 |
92 | verify(mockFileSystem).getRootDirectories();
93 | assertEquals(root, returned);
94 | }
95 |
96 | @Test
97 | public void testGetRoot_relative() {
98 | Path p = new GlusterPath(mockFileSystem, "foo/bar");
99 | Path returned = p.getRoot();
100 |
101 | verify(mockFileSystem, times(0)).getRootDirectories();
102 | assertEquals(null, returned);
103 | }
104 |
105 | @Test
106 | public void testGetFilesystem() {
107 | Path p = new GlusterPath(mockFileSystem, "foo/bar");
108 | assertTrue(p.getFileSystem() == mockFileSystem);
109 | }
110 |
111 | @Test
112 | public void testToUri() throws URISyntaxException {
113 | GlusterFileSystemProvider mockProvider = mock(GlusterFileSystemProvider.class);
114 | String scheme = GlusterFileSystemProvider.GLUSTER;
115 | doReturn(scheme).when(mockProvider).getScheme();
116 | doReturn(mockProvider).when(mockFileSystem).provider();
117 |
118 | String host = "localhost";
119 | doReturn(host).when(mockFileSystem).getHost();
120 |
121 | String volname = "foo";
122 | doReturn(volname).when(mockFileSystem).getVolname();
123 |
124 | String path = "/foo/bar";
125 | GlusterPath p = spy(new GlusterPath(mockFileSystem, path));
126 | doReturn(mockFileSystem).when(p).getFileSystem();
127 | doReturn(path).when(p).toString();
128 |
129 | String authority = host + ":" + volname;
130 | URI expected = new URI(scheme, authority, path, null, null);
131 | assertEquals(expected, p.toUri());
132 | }
133 |
134 | @Test
135 | public void testGetFileName() {
136 | Path p = new GlusterPath(mockFileSystem, "/");
137 | assertEquals(null, p.getFileName());
138 |
139 | p = new GlusterPath(mockFileSystem, "/bar");
140 | assertEquals(new GlusterPath(mockFileSystem, "bar"), p.getFileName());
141 |
142 | p = new GlusterPath(mockFileSystem, "foo/bar");
143 | assertEquals(new GlusterPath(mockFileSystem, "bar"), p.getFileName());
144 | }
145 |
146 | @Test
147 | public void testGetParent() {
148 | List roots = new LinkedList();
149 | roots.add(mockGlusterPath);
150 | doReturn(roots).when(mockFileSystem).getRootDirectories();
151 |
152 | Path p = new GlusterPath(mockFileSystem, "/");
153 | assertEquals(mockGlusterPath, p.getParent());
154 |
155 | p = new GlusterPath(mockFileSystem, "/bar");
156 | assertEquals(mockGlusterPath, p.getParent());
157 |
158 | p = new GlusterPath(mockFileSystem, "/bar/baz");
159 | assertEquals(new GlusterPath(mockFileSystem, "/bar"), p.getParent());
160 |
161 | p = new GlusterPath(mockFileSystem, "foo/bar");
162 | assertEquals(new GlusterPath(mockFileSystem, "foo"), p.getParent());
163 |
164 | p = new GlusterPath(mockFileSystem, "bar");
165 | assertEquals(null, p.getParent());
166 |
167 | verify(mockFileSystem, times(2)).getRootDirectories();
168 | }
169 |
170 | @Test
171 | public void testGetNameCount() {
172 | Path p = new GlusterPath(mockFileSystem, "/");
173 | assertEquals(0, p.getNameCount());
174 |
175 | p = new GlusterPath(mockFileSystem, "/bar");
176 | assertEquals(1, p.getNameCount());
177 |
178 | p = new GlusterPath(mockFileSystem, "/foo/bar");
179 | assertEquals(2, p.getNameCount());
180 |
181 | p = new GlusterPath(mockFileSystem, "foo/bar");
182 | assertEquals(2, p.getNameCount());
183 | }
184 |
185 | @Test(expected = IllegalArgumentException.class)
186 | public void testGetName_noName() {
187 | Path p = new GlusterPath(mockFileSystem, "/");
188 | p.getName(0);
189 | }
190 |
191 | @Test(expected = IllegalArgumentException.class)
192 | public void testGetName_negative() {
193 | Path p = new GlusterPath(mockFileSystem, "/foo");
194 | p.getName(-1);
195 | }
196 |
197 | @Test(expected = IllegalArgumentException.class)
198 | public void testGetName_excessive() {
199 | Path p = new GlusterPath(mockFileSystem, "/foo");
200 | p.getName(4);
201 | }
202 |
203 | @Test
204 | public void testGetName() {
205 | Path p = new GlusterPath(mockFileSystem, "/foo/bar/baz");
206 | assertEquals(new GlusterPath(mockFileSystem, new String[]{"foo"}, true), p.getName(0));
207 | assertEquals(new GlusterPath(mockFileSystem, new String[]{"foo", "bar"}, true), p.getName(1));
208 | assertEquals(new GlusterPath(mockFileSystem, new String[]{"foo", "bar", "baz"}, true), p.getName(2));
209 |
210 | p = new GlusterPath(mockFileSystem, "foo/bar/baz");
211 | assertEquals(new GlusterPath(mockFileSystem, new String[]{"foo"}, false), p.getName(0));
212 | assertEquals(new GlusterPath(mockFileSystem, new String[]{"foo", "bar"}, false), p.getName(1));
213 | assertEquals(new GlusterPath(mockFileSystem, new String[]{"foo", "bar", "baz"}, false), p.getName(2));
214 | }
215 |
216 | @Test(expected = IllegalArgumentException.class)
217 | public void testSubpath_noName() {
218 | Path p = new GlusterPath(mockFileSystem, "/");
219 | p.getName(0);
220 | }
221 |
222 | @Test(expected = IllegalArgumentException.class)
223 | public void testSubpath_negativeStart() {
224 | Path p = new GlusterPath(mockFileSystem, "/foo");
225 | p.subpath(-1, 0);
226 | }
227 |
228 | @Test(expected = IllegalArgumentException.class)
229 | public void testSubpath_negativeEnd() {
230 | Path p = new GlusterPath(mockFileSystem, "/foo");
231 | p.subpath(0, -1);
232 | }
233 |
234 | @Test(expected = IllegalArgumentException.class)
235 | public void testSubpath_excessiveStart() {
236 | Path p = new GlusterPath(mockFileSystem, "/foo");
237 | p.subpath(4, 5);
238 | }
239 |
240 | @Test(expected = IllegalArgumentException.class)
241 | public void testSubpath_excessiveEnd() {
242 | Path p = new GlusterPath(mockFileSystem, "/foo");
243 | p.subpath(0, 4);
244 | }
245 |
246 | @Test(expected = IllegalArgumentException.class)
247 | public void testSubpath_Inverted() {
248 | Path p = new GlusterPath(mockFileSystem, "/foo");
249 | p.subpath(2, 1);
250 | }
251 |
252 | @Test
253 | public void testSubpath() {
254 | Path p = new GlusterPath(mockFileSystem, "/foo/bar/baz");
255 | assertEquals(new GlusterPath(mockFileSystem, new String[]{"foo"}, true), p.subpath(0, 1));
256 | assertEquals(new GlusterPath(mockFileSystem, new String[]{"bar"}, true), p.subpath(1, 2));
257 | assertEquals(new GlusterPath(mockFileSystem, new String[]{"bar", "baz"}, true), p.subpath(1, 3));
258 |
259 | p = new GlusterPath(mockFileSystem, "foo/bar/baz");
260 | assertEquals(new GlusterPath(mockFileSystem, new String[]{"foo"}, false), p.subpath(0, 1));
261 | assertEquals(new GlusterPath(mockFileSystem, new String[]{"bar"}, false), p.subpath(1, 2));
262 | assertEquals(new GlusterPath(mockFileSystem, new String[]{"bar", "baz"}, false), p.subpath(1, 3));
263 | }
264 |
265 | @Test
266 | public void testStartsWith() {
267 | Path p1 = new GlusterPath(mockFileSystem, "/");
268 | assertTrue(p1.startsWith(p1));
269 |
270 | Path p2 = new GlusterPath(mockFileSystem, "/foo");
271 | assertFalse(p1.startsWith(p2));
272 |
273 | assertTrue(p2.startsWith(p1));
274 |
275 | p1 = new GlusterPath(mockFileSystem, "/bar");
276 | assertFalse(p1.startsWith(p2));
277 | }
278 |
279 | @Test
280 | public void testStartsWith_String() {
281 | Path p1 = new GlusterPath(mockFileSystem, "/");
282 | assertTrue(p1.startsWith("/"));
283 |
284 | Path p2 = new GlusterPath(mockFileSystem, "/foo");
285 | assertFalse(p1.startsWith("/foo"));
286 |
287 | assertTrue(p2.startsWith("/"));
288 |
289 | p1 = new GlusterPath(mockFileSystem, "/bar");
290 | assertFalse(p1.startsWith("/foo"));
291 | }
292 |
293 | @Test
294 | public void testEndsWith() {
295 | Path p1 = new GlusterPath(mockFileSystem, "/");
296 | assertTrue(p1.endsWith(p1));
297 |
298 | Path p2 = new GlusterPath(mockFileSystem, "/foo");
299 | assertFalse(p1.endsWith(p2));
300 |
301 | p1 = new GlusterPath(mockFileSystem, "/foo");
302 | assertTrue(p1.endsWith(p2));
303 |
304 | p2 = new GlusterPath(mockFileSystem, "foo");
305 | assertTrue(p1.endsWith(p2));
306 |
307 | p1 = new GlusterPath(mockFileSystem, "foo/bar");
308 | p2 = new GlusterPath(mockFileSystem, "bar");
309 | assertTrue(p1.endsWith(p2));
310 |
311 | p2 = new GlusterPath(mockFileSystem, "/bar");
312 | assertFalse(p1.endsWith(p2));
313 | }
314 |
315 | @Test
316 | public void testNormalize() {
317 | Path p = new GlusterPath(mockFileSystem, "foo//bar");
318 | assertEquals(new GlusterPath(mockFileSystem, "foo/bar"), p.normalize());
319 |
320 | p = new GlusterPath(mockFileSystem, "foo/./bar");
321 | assertEquals(new GlusterPath(mockFileSystem, "foo/bar"), p.normalize());
322 |
323 | p = new GlusterPath(mockFileSystem, "foo/././bar");
324 | assertEquals(new GlusterPath(mockFileSystem, "foo/bar"), p.normalize());
325 |
326 | p = new GlusterPath(mockFileSystem, "foo/baz/../bar");
327 | assertEquals(new GlusterPath(mockFileSystem, "foo/bar"), p.normalize());
328 |
329 | p = new GlusterPath(mockFileSystem, "foo/baz/../baz/../bar");
330 | assertEquals(new GlusterPath(mockFileSystem, "foo/bar"), p.normalize());
331 | }
332 |
333 | @Test
334 | public void testResolve() {
335 | Path path = new GlusterPath(mockFileSystem, "/");
336 | Path otherPath = new GlusterPath(mockFileSystem, "/bar");
337 |
338 | assertEquals(otherPath, path.resolve(otherPath));
339 |
340 | otherPath = new GlusterPath(mockFileSystem, "bar");
341 | assertEquals(new GlusterPath(mockFileSystem, "/bar"), path.resolve(otherPath));
342 |
343 | otherPath = new GlusterPath(mockFileSystem, "");
344 | assertEquals(path, path.resolve(otherPath));
345 | }
346 |
347 | @Test
348 | public void testResolve_string() {
349 | Path path = new GlusterPath(mockFileSystem, "/");
350 |
351 | assertEquals(new GlusterPath(mockFileSystem, "/bar"), path.resolve("/bar"));
352 |
353 | assertEquals(new GlusterPath(mockFileSystem, "/bar"), path.resolve("bar"));
354 |
355 | assertEquals(path, path.resolve(""));
356 |
357 | path = new GlusterPath(mockFileSystem, "/foo");
358 | assertEquals(new GlusterPath(mockFileSystem, "/foo/bar"), path.resolve("bar"));
359 | }
360 |
361 | @Test
362 | public void testResolveSibling() {
363 | Path p = new GlusterPath(mockFileSystem, "foo/bar");
364 | Path other = new GlusterPath(mockFileSystem, "baz");
365 | Path finalPath = p.resolveSibling(other);
366 | assertEquals(new GlusterPath(mockFileSystem, "foo/baz"), finalPath);
367 | }
368 |
369 | @Test
370 | public void testResolveSibling_string() {
371 | Path p = new GlusterPath(mockFileSystem, "foo/bar");
372 | Path finalPath = p.resolveSibling("baz");
373 | assertEquals(new GlusterPath(mockFileSystem, "foo/baz"), finalPath);
374 | }
375 |
376 | @Test(expected = IllegalArgumentException.class)
377 | public void testRelativize_otherIsRelative() {
378 | Path p = new GlusterPath(mockFileSystem, "/foo/bar");
379 | Path other = new GlusterPath(mockFileSystem, "foo/baz");
380 | p.relativize(other);
381 | }
382 |
383 | @Test(expected = IllegalArgumentException.class)
384 | public void testRelativize_thisIsRelative() {
385 | Path p = new GlusterPath(mockFileSystem, "foo/bar");
386 | Path other = new GlusterPath(mockFileSystem, "/foo/baz");
387 | p.relativize(other);
388 | }
389 |
390 | @Test(expected = IllegalArgumentException.class)
391 | public void testRelativize_bothAreRelative() {
392 | Path p = new GlusterPath(mockFileSystem, "foo/bar");
393 | Path other = new GlusterPath(mockFileSystem, "foo/baz");
394 | p.relativize(other);
395 | }
396 |
397 | @Test
398 | public void testRelativize() {
399 | Path p = new GlusterPath(mockFileSystem, "/foo/bar");
400 | Path other = new GlusterPath(mockFileSystem, "/foo/baz");
401 |
402 | Path relativePath = p.relativize(other);
403 | assertEquals(new GlusterPath(mockFileSystem, "../baz"), relativePath);
404 |
405 | other = new GlusterPath(mockFileSystem, "/foo/bar/baz");
406 | relativePath = p.relativize(other);
407 | assertEquals(new GlusterPath(mockFileSystem, "baz"), relativePath);
408 |
409 | p = new GlusterPath(mockFileSystem, "/foo/bar");
410 | other = new GlusterPath(mockFileSystem, "/foo");
411 | relativePath = p.relativize(other);
412 | assertEquals(new GlusterPath(mockFileSystem, ".."), relativePath);
413 |
414 | p = new GlusterPath(mockFileSystem, "/foo/bar");
415 | other = new GlusterPath(mockFileSystem, "/baz");
416 | relativePath = p.relativize(other);
417 | assertEquals(new GlusterPath(mockFileSystem, "../../baz"), relativePath);
418 |
419 | p = new GlusterPath(mockFileSystem, "/foo");
420 | other = new GlusterPath(mockFileSystem, "/bar/baz");
421 | relativePath = p.relativize(other);
422 | assertEquals(new GlusterPath(mockFileSystem, "../bar/baz"), relativePath);
423 | }
424 |
425 | @Test(expected = UnsupportedOperationException.class)
426 | public void testToAbsolutePath_whenRelative() {
427 | Path p = new GlusterPath(mockFileSystem, "foo");
428 | p.toAbsolutePath();
429 | }
430 |
431 | @Test
432 | public void testToAbsolutePath() {
433 | Path p = new GlusterPath(mockFileSystem, "/foo");
434 | assertEquals(p, p.toAbsolutePath());
435 | }
436 |
437 | @Test
438 | public void testIterator() {
439 | Path p = new GlusterPath(mockFileSystem, "/foo/bar");
440 | Iterator it = p.iterator();
441 | assertEquals(new GlusterPath(mockFileSystem, "foo"), it.next());
442 | assertEquals(new GlusterPath(mockFileSystem, "bar"), it.next());
443 |
444 | p = new GlusterPath(mockFileSystem, "/");
445 | it = p.iterator();
446 | assertFalse(it.hasNext());
447 | }
448 |
449 | @Test(expected = ClassCastException.class)
450 | public void testCompareTo_differentProvider() {
451 | Path path = new GlusterPath(mockFileSystem, "");
452 | Path zipfile = Paths.get("/codeSamples/zipfs/zipfstest.zip");
453 | path.compareTo(zipfile);
454 | }
455 |
456 | @Test
457 | public void testCompareTo() {
458 | Path p = new GlusterPath(mockFileSystem, "/foo");
459 | Path other = new GlusterPath(mockFileSystem, "/bar");
460 | assertTrue(p.compareTo(other) > 0);
461 |
462 | p = new GlusterPath(mockFileSystem, "/bar");
463 | other = new GlusterPath(mockFileSystem, "/foo");
464 | assertTrue(p.compareTo(other) < 0);
465 |
466 | p = new GlusterPath(mockFileSystem, "/foo");
467 | other = new GlusterPath(mockFileSystem, "/foo");
468 | assertEquals(0, p.compareTo(other));
469 |
470 | p = new GlusterPath(mockFileSystem, "/");
471 | other = new GlusterPath(mockFileSystem, "/foo");
472 | assertTrue(p.compareTo(other) < 0);
473 |
474 | p = new GlusterPath(mockFileSystem, "/foo");
475 | other = new GlusterPath(mockFileSystem, "/");
476 | assertTrue(p.compareTo(other) > 0);
477 | }
478 |
479 | @Test
480 | public void testToString_whenPathString() {
481 | String pathString = "/bar/baz";
482 | Path p = new GlusterPath(mockFileSystem, pathString);
483 | String filesystemString = "gluster://127.0.2.1:foo";
484 | doReturn(filesystemString).when(mockFileSystem).toString();
485 | assertEquals(pathString, p.toString());
486 | }
487 |
488 | @Test
489 | public void testToString_whenNoPathString() {
490 | Path p = new GlusterPath(mockFileSystem, new String[]{"a", "b"}, true);
491 | assertEquals("/a/b", p.toString());
492 | }
493 |
494 | @Test
495 | public void testGetString_whenPathString() {
496 | String string = "/foo/bar";
497 | GlusterPath path = new GlusterPath(mockFileSystem, string);
498 | path.setParts(new String[]{"a", "b"});
499 | assertEquals(string, path.getString());
500 | }
501 |
502 | @Test
503 | public void testGetString_whenNoPathString() {
504 | GlusterPath path = new GlusterPath(mockFileSystem, new String[]{"a", "b"}, false);
505 | assertEquals("a/b", path.getString());
506 | }
507 |
508 | @Test
509 | public void testRegisterWatchService() throws IOException {
510 | GlusterPath path = spy(new GlusterPath(mockFileSystem, new String[]{"foo", "bar"}, true));
511 | GlusterWatchService mockWatchService = mock(GlusterWatchService.class);
512 | doNothing().when(path).guardRegisterWatchService(mockWatchService);
513 |
514 | WatchEvent.Kind[] kinds = new WatchEvent.Kind[]{StandardWatchEventKinds.ENTRY_MODIFY};
515 |
516 | doNothing().when(path).guardRegisterWatchDirectory();
517 |
518 | WatchKey mockKey = mock(WatchKey.class);
519 | doReturn(mockKey).when(mockWatchService).registerPath(path, kinds);
520 |
521 | WatchKey watchKey = path.register(mockWatchService, kinds);
522 |
523 | assertEquals(mockKey, watchKey);
524 |
525 | verify(path).guardRegisterWatchService(mockWatchService);
526 | verify(path).guardRegisterWatchDirectory();
527 | verify(mockWatchService).registerPath(path, kinds);
528 | }
529 |
530 | @Test(expected = UnsupportedOperationException.class)
531 | public void testGuardRegisterWatchService() {
532 | GlusterPath path = spy(new GlusterPath(mockFileSystem, new String[]{}, false));
533 | WatchService mockWatchService = mock(WatchService.class);
534 |
535 | path.guardRegisterWatchService(mockWatchService);
536 | }
537 |
538 | }
539 |
540 |
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/test/java/com/peircean/glusterfs/GlusterWatchKeyTest.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import org.junit.Assert;
4 | import org.junit.Before;
5 | import org.junit.Test;
6 | import org.junit.runner.RunWith;
7 | import org.mockito.Mock;
8 | import org.powermock.api.mockito.PowerMockito;
9 | import org.powermock.core.classloader.annotations.PrepareForTest;
10 | import org.powermock.modules.junit4.PowerMockRunner;
11 |
12 | import java.io.IOException;
13 | import java.nio.file.DirectoryStream;
14 | import java.nio.file.Files;
15 | import java.nio.file.Path;
16 | import java.nio.file.WatchEvent;
17 | import java.util.*;
18 |
19 | import static junit.framework.Assert.*;
20 | import static org.mockito.Matchers.isA;
21 | import static org.mockito.Mockito.*;
22 | import static org.powermock.api.mockito.PowerMockito.doReturn;
23 | import static org.powermock.api.mockito.PowerMockito.when;
24 |
25 | @RunWith(PowerMockRunner.class)
26 | @PrepareForTest({GlusterWatchKey.class, Files.class, LinkedList.class})
27 | public class GlusterWatchKeyTest {
28 | @Mock
29 | GlusterPath mockPath;
30 |
31 | @Mock
32 | WatchEvent.Kind mockKind;
33 |
34 | WatchEvent.Kind[] mockKinds = new WatchEvent.Kind[]{mockKind};
35 |
36 | GlusterWatchKey key;
37 |
38 | @Before
39 | public void setUp() {
40 | key = PowerMockito.spy(new GlusterWatchKey(mockPath, mockKinds));
41 | }
42 |
43 | @Test
44 | public void testUpdate_whenIOException() throws IOException {
45 | PowerMockito.mockStatic(Files.class);
46 | when(Files.newDirectoryStream(mockPath)).thenThrow(new IOException());
47 |
48 | assertFalse(key.update());
49 |
50 | PowerMockito.verifyStatic();
51 | Files.newDirectoryStream(mockPath);
52 | }
53 |
54 | @Test
55 | public void testUpdate_whenNoEvents() throws Exception {
56 | updateHelper(UpdateTestMode.NONE);
57 | }
58 |
59 | @Test
60 | public void testUpdate_whenExistingEvent() throws Exception {
61 | updateHelper(UpdateTestMode.CHANGED);
62 | }
63 |
64 | @Test
65 | public void testUpdate_whenDeletedEvent() throws Exception {
66 | updateHelper(UpdateTestMode.DELETED);
67 | }
68 |
69 | void updateHelper(UpdateTestMode mode) throws Exception {
70 | boolean deleted = false;
71 | boolean existing = false;
72 | switch (mode) {
73 | case CHANGED:
74 | existing = true;
75 | break;
76 | case DELETED:
77 | deleted = true;
78 | break;
79 | }
80 | LinkedList mockPaths = new LinkedList<>();
81 | Path onePath = mock(Path.class);
82 | mockPaths.add(onePath);
83 |
84 | LinkedList mockFiles = mock(LinkedList.class);
85 | PowerMockito.whenNew(LinkedList.class).withNoArguments().thenReturn(mockFiles);
86 |
87 | Path mockEventPath = mock(Path.class);
88 | Set eventsKeys = new HashSet();
89 | eventsKeys.add(mockEventPath);
90 | HashMap mockEvents = mock(HashMap.class);
91 | doReturn(eventsKeys).when(mockEvents).keySet();
92 | doReturn(deleted).when(key).checkDeleted(mockFiles, mockEventPath);
93 | key.setEvents(mockEvents);
94 |
95 | doReturn(existing).when(key).processExistingFile(mockFiles, onePath);
96 |
97 | DirectoryStream mockDirectoryStream = mock(DirectoryStream.class);
98 | doReturn(mockPaths.iterator()).when(mockDirectoryStream).iterator();
99 |
100 | PowerMockito.mockStatic(Files.class);
101 | when(Files.newDirectoryStream(mockPath)).thenReturn(mockDirectoryStream);
102 |
103 | switch (mode) {
104 | case CHANGED:
105 | case DELETED:
106 | assertTrue(key.update());
107 | break;
108 | default:
109 | assertFalse(key.update());
110 | }
111 |
112 | verify(mockFiles, never()).add(isA(Path.class));
113 | verify(mockDirectoryStream).iterator();
114 | verify(key).processExistingFile(mockFiles, onePath);
115 | verify(mockEvents).keySet();
116 | verify(key).checkDeleted(mockFiles, mockEventPath);
117 |
118 | PowerMockito.verifyStatic();
119 | Files.newDirectoryStream(mockPath);
120 |
121 | PowerMockito.verifyNew(LinkedList.class);
122 | }
123 |
124 | @Test
125 | public void testProcessExistingFile() {
126 |
127 | }
128 |
129 | @Test
130 | public void testCheckDeleted() {
131 |
132 | }
133 |
134 | @Test
135 | public void testCheckCreated() {
136 |
137 | }
138 |
139 | @Test
140 | public void testCheckModified() {
141 |
142 | }
143 |
144 | @Test
145 | public void testKindsContains() {
146 |
147 | }
148 |
149 | @Test
150 | public void testPollEvents_whenNotReady() {
151 | key.setReady(false);
152 | assertTrue(key.pollEvents().isEmpty());
153 | }
154 |
155 | @Test
156 | public void testPollEvents_whenReady() {
157 | key.setReady(true);
158 |
159 | LinkedList> mockEvents = mock(LinkedList.class);
160 | doReturn(mockEvents).when(key).findPendingEvents();
161 |
162 | List> events = key.pollEvents();
163 | assertEquals(mockEvents, events);
164 |
165 | assertFalse(key.isReady());
166 |
167 | verify(key).findPendingEvents();
168 | }
169 |
170 | @Test
171 | public void testFindPendingEvents() {
172 |
173 | }
174 |
175 | @Test
176 | public void testReset_whenInvalid() {
177 | key.setValid(false);
178 | Assert.assertFalse(key.reset());
179 | }
180 |
181 | @Test
182 | public void testReset_whenReady() {
183 | WatchEvent.Kind[] kinds = new WatchEvent.Kind[]{mock(WatchEvent.Kind.class)};
184 | GlusterPath path = mock(GlusterPath.class);
185 |
186 | GlusterWatchKey key = new GlusterWatchKey(path, kinds);
187 | key.setValid(true);
188 | key.setReady(true);
189 | Assert.assertFalse(key.reset());
190 | }
191 |
192 | @Test
193 | public void testCancel() {
194 | WatchEvent.Kind[] kinds = new WatchEvent.Kind[]{mock(WatchEvent.Kind.class)};
195 | GlusterPath path = mock(GlusterPath.class);
196 |
197 | GlusterWatchKey key = new GlusterWatchKey(path, kinds);
198 | key.setValid(true);
199 | key.setReady(false);
200 | assertTrue(key.reset());
201 | assertTrue(key.isReady());
202 | }
203 |
204 | }
205 |
206 | enum UpdateTestMode {
207 | NONE, CHANGED, DELETED
208 | }
--------------------------------------------------------------------------------
/glusterfs-java-filesystem/src/test/java/com/peircean/glusterfs/GlusterWatchServiceTest.java:
--------------------------------------------------------------------------------
1 | package com.peircean.glusterfs;
2 |
3 | import org.junit.Assert;
4 | import org.junit.Test;
5 | import org.junit.runner.RunWith;
6 | import org.mockito.Mockito;
7 | import org.powermock.api.mockito.PowerMockito;
8 | import org.powermock.core.classloader.annotations.PrepareForTest;
9 | import org.powermock.modules.junit4.PowerMockRunner;
10 |
11 | import java.io.IOException;
12 | import java.nio.file.ClosedWatchServiceException;
13 | import java.nio.file.StandardWatchEventKinds;
14 | import java.nio.file.WatchEvent;
15 | import java.nio.file.WatchKey;
16 | import java.util.concurrent.TimeUnit;
17 |
18 | import static org.junit.Assert.assertEquals;
19 | import static org.junit.Assert.assertFalse;
20 | import static org.powermock.api.mockito.PowerMockito.doReturn;
21 | import static org.powermock.api.mockito.PowerMockito.mock;
22 |
23 | @RunWith(PowerMockRunner.class)
24 | @PrepareForTest({GlusterWatchService.class, Thread.class})
25 | public class GlusterWatchServiceTest {
26 |
27 | GlusterWatchService watchService = PowerMockito.spy(new GlusterWatchService());
28 |
29 | @Test(expected = ClosedWatchServiceException.class)
30 | public void testRegisterPath_whenNotRunning() {
31 | watchService.setRunning(false);
32 | GlusterPath mockPath = mock(GlusterPath.class);
33 | watchService.registerPath(mockPath);
34 | }
35 |
36 | @Test
37 | public void testRegisterPath() {
38 | watchService.setRunning(true);
39 | GlusterPath mockPath = mock(GlusterPath.class);
40 | WatchEvent.Kind mockKind = mock(WatchEvent.Kind.class);
41 | watchService.registerPath(mockPath, mockKind);
42 | GlusterWatchKey event = watchService.getPaths().iterator().next();
43 | assertEquals(mockPath, event.getPath());
44 | assertEquals(mockKind, event.getKinds()[0]);
45 | }
46 |
47 | @Test
48 | public void testRegisterPath_whenPathExists() {
49 | watchService.setRunning(true);
50 | GlusterPath mockPath = mock(GlusterPath.class);
51 | GlusterWatchKey keyFix = new GlusterWatchKey(mockPath, new WatchEvent.Kind[]{StandardWatchEventKinds.ENTRY_MODIFY});
52 | watchService.getPaths().add(keyFix);
53 | watchService.registerPath(mockPath, StandardWatchEventKinds.ENTRY_CREATE);
54 | GlusterWatchKey event = watchService.getPaths().iterator().next();
55 | assertEquals(mockPath, event.getPath());
56 | assertEquals(StandardWatchEventKinds.ENTRY_CREATE, event.getKinds()[0]);
57 |
58 | }
59 |
60 | @Test
61 | public void testClose_whenNotRunning() throws IOException {
62 | watchService.setRunning(false);
63 | GlusterWatchKey mockKey = mock(GlusterWatchKey.class);
64 | watchService.getPaths().add(mockKey);
65 | watchService.close();
66 | Mockito.verify(mockKey, Mockito.never()).cancel();
67 | }
68 |
69 | @Test
70 | public void testClose() throws IOException {
71 | watchService.setRunning(true);
72 | GlusterWatchKey mockKey = mock(GlusterWatchKey.class);
73 | watchService.getPaths().add(mockKey);
74 | watchService.close();
75 | Mockito.verify(mockKey).cancel();
76 | assertFalse(watchService.isRunning());
77 | }
78 |
79 | @Test
80 | public void testPopPending_whenNonePending() {
81 | WatchKey key = watchService.popPending();
82 | assertEquals(null, key);
83 | assertEquals(0, watchService.getPendingPaths().size());
84 | }
85 |
86 | @Test
87 | public void testPopPending() {
88 | GlusterPath mockPath = mock(GlusterPath.class);
89 | GlusterWatchKey keyFix = new GlusterWatchKey(mockPath, new WatchEvent.Kind[]{StandardWatchEventKinds.ENTRY_CREATE});
90 | watchService.getPendingPaths().add(keyFix);
91 | WatchKey key = watchService.popPending();
92 | assertEquals(keyFix, key);
93 | assertEquals(0, watchService.getPendingPaths().size());
94 | }
95 |
96 | @Test(expected = ClosedWatchServiceException.class)
97 | public void testPoll_whenNotRunning() {
98 | watchService.setRunning(false);
99 | watchService.poll();
100 | }
101 |
102 | @Test
103 | public void testPoll_whenPending() {
104 | watchService.setRunning(true);
105 | GlusterWatchKey mockKey = mock(GlusterWatchKey.class);
106 | watchService.getPendingPaths().add(mockKey);
107 | WatchKey key = watchService.poll();
108 | assertEquals(mockKey, key);
109 | }
110 |
111 | @Test
112 | public void testPoll_whenReadyAndEvent() {
113 | watchService.setRunning(true);
114 | GlusterWatchKey mockKey = mock(GlusterWatchKey.class);
115 | watchService.getPaths().add(mockKey);
116 | doReturn(null).doReturn(mockKey).when(watchService).popPending();
117 | doReturn(true).when(mockKey).isValid();
118 | doReturn(true).when(mockKey).isReady();
119 | doReturn(true).when(mockKey).update();
120 |
121 | WatchKey key = watchService.poll();
122 |
123 | assertEquals(mockKey, key);
124 |
125 | Mockito.verify(mockKey).isValid();
126 | Mockito.verify(mockKey).isReady();
127 | Mockito.verify(mockKey).update();
128 | }
129 |
130 | @Test
131 | public void testPoll_whenReadyAndNoEvent() {
132 | watchService.setRunning(true);
133 | GlusterWatchKey mockKey = mock(GlusterWatchKey.class);
134 | watchService.getPaths().add(mockKey);
135 | doReturn(true).when(mockKey).isValid();
136 | doReturn(true).when(mockKey).isReady();
137 | doReturn(false).when(mockKey).update();
138 |
139 | WatchKey key = watchService.poll();
140 |
141 | assertEquals(null, key);
142 |
143 | Mockito.verify(mockKey).isValid();
144 | Mockito.verify(mockKey).isReady();
145 | Mockito.verify(mockKey).update();
146 | }
147 |
148 | @Test(expected = ClosedWatchServiceException.class)
149 | public void testPollTimeout_whenClosed() {
150 | long timeout = 150L;
151 | TimeUnit unit = TimeUnit.MILLISECONDS;
152 | doReturn(timeout).when(watchService).timeoutToMillis(timeout, unit);
153 | watchService.setRunning(false);
154 | watchService.poll(timeout, unit);
155 | }
156 |
157 | @Test
158 | public void testPollTimeout() throws InterruptedException {
159 | long timeout = 150L;
160 | TimeUnit unit = TimeUnit.MILLISECONDS;
161 | // doReturn(timeout).when(watchService).timeoutToMillis(timeout, unit);
162 |
163 | WatchKey mockKey = mock(WatchKey.class);
164 | PowerMockito.when(watchService.poll()).thenReturn(null).thenReturn(mockKey);
165 |
166 | PowerMockito.spy(Thread.class);
167 | PowerMockito.doThrow(new InterruptedException()).when(Thread.class);
168 | Thread.sleep(GlusterWatchService.PERIOD);
169 |
170 | WatchKey key = watchService.poll(timeout, unit);
171 |
172 | assertEquals(mockKey, key);
173 |
174 | Mockito.verify(watchService, Mockito.times(2)).poll();
175 | // Mockito.verify(watchService).timeoutToMillis(timeout, unit);
176 |
177 | PowerMockito.verifyStatic(Mockito.times(1));
178 | Thread.sleep(GlusterWatchService.PERIOD);
179 | }
180 |
181 | @Test(expected = ClosedWatchServiceException.class)
182 | public void testTake_whenClosed() {
183 | watchService.setRunning(false);
184 | watchService.take();
185 | }
186 |
187 | @Test
188 | public void testTake() throws Exception {
189 | WatchKey mockKey = mock(WatchKey.class);
190 | doReturn(null).doReturn(mockKey).when(watchService).poll();
191 |
192 | PowerMockito.spy(Thread.class);
193 | PowerMockito.doThrow(new InterruptedException()).when(Thread.class);
194 | Thread.sleep(GlusterWatchService.PERIOD);
195 |
196 | WatchKey key = watchService.take();
197 |
198 | assertEquals(mockKey, key);
199 |
200 | Mockito.verify(watchService, Mockito.times(2)).poll();
201 |
202 | PowerMockito.verifyStatic();
203 | Thread.sleep(GlusterWatchService.PERIOD);
204 | }
205 |
206 | @Test
207 | public void testTimeoutToMillis() {
208 | long time = 12345L;
209 | Assert.assertEquals(-1,
210 | watchService.timeoutToMillis(time, TimeUnit.NANOSECONDS));
211 | Assert.assertEquals(-1,
212 | watchService.timeoutToMillis(time, TimeUnit.MICROSECONDS));
213 | Assert.assertEquals(time,
214 | watchService.timeoutToMillis(time, TimeUnit.MILLISECONDS));
215 | Assert.assertEquals(time * GlusterWatchService.MILLIS_PER_SECOND,
216 | watchService.timeoutToMillis(time, TimeUnit.SECONDS));
217 | Assert.assertEquals(time * GlusterWatchService.MILLIS_PER_MINUTE,
218 | watchService.timeoutToMillis(time, TimeUnit.MINUTES));
219 | Assert.assertEquals(time * GlusterWatchService.MILLIS_PER_HOUR,
220 | watchService.timeoutToMillis(time, TimeUnit.HOURS));
221 | Assert.assertEquals(time * GlusterWatchService.MILLIS_PER_DAY,
222 | watchService.timeoutToMillis(time, TimeUnit.DAYS));
223 | }
224 | }
225 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | com.peircean.glusterfs
6 | glusterfs-java-filesystem-project
7 | 1.0.5-SNAPSHOT
8 |
9 | glusterfs-java-filesystem
10 | glusterfs-java-filesystem-example
11 |
12 | pom
13 |
14 |
15 | org.sonatype.oss
16 | oss-parent
17 | 7
18 |
19 |
20 | ${project.artifactId}
21 | glusterfs-java-filesystem aims to be a complete implementation of a Java7/NIO.2 File System Provider
22 | backed by GlusterFS via libgfapi-jni
23 |
24 |
25 |
26 | BSD-style
27 | https://github.com/semiosis/glusterfs-java-filesystem/blob/master/LICENSE.txt
28 | A permissive open source license
29 | repo
30 |
31 |
32 |
33 | 2013
34 |
35 |
36 | https://github.com/semiosis/glusterfs-java-filesystem
37 | scm:git:https://github.com/semiosis/glusterfs-java-filesystem.git
38 | scm:git:git@github.com:semiosis/glusterfs-java-filesystem.git
39 | HEAD
40 |
41 |
42 |
43 |
44 | zuckerman
45 | Louis Zuckerman
46 | me@louiszuckerman.com
47 | http://about.me/louiszuckerman
48 | GMT-5
49 |
50 |
51 |
52 |
53 |
54 |
55 | org.apache.maven.plugins
56 | maven-surefire-plugin
57 | 2.16
58 |
59 | true
60 | once
61 | -ea
62 | true
63 | ${project.build.directory}
64 |
65 | **/*Test.java
66 |
67 |
68 |
69 |
70 | org.apache.maven.plugins
71 | maven-compiler-plugin
72 | 3.1
73 |
74 | 1.7
75 | 1.7
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | junit
84 | junit
85 | 4.11
86 | test
87 |
88 |
89 |
90 |
91 |
92 | release
93 |
94 |
95 |
96 | org.apache.maven.plugins
97 | maven-release-plugin
98 | 2.5
99 |
100 | true
101 |
102 |
103 |
104 | org.apache.maven.plugins
105 | maven-gpg-plugin
106 | 1.5
107 |
108 |
109 | sign-artifacts
110 | verify
111 |
112 | sign
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
--------------------------------------------------------------------------------
/vagrant-provisioner.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | add-apt-repository -y ppa:gluster/glusterfs-3.8
4 | apt-get update
5 | # apt-get -y dist-upgrade
6 | apt-get -y install glusterfs-server
7 | sleep 2
8 |
9 | sed -i 's/\(end-volume\)/ option rpc-auth-allow-insecure on\n\1/' /etc/glusterfs/glusterd.vol
10 | service glusterfs-server restart
11 | sleep 2
12 |
13 | gluster volume create foo ${1}:/var/tmp/foo force
14 | gluster volume set foo server.allow-insecure on
15 | gluster volume start foo
16 | sleep 2
17 |
18 | mkdir -v /mnt/foo
19 | mount -t glusterfs localhost:foo /mnt/foo && echo Mounted glusterfs volume at /mnt/foo.
20 | chmod -v ugo+w /mnt/foo
21 |
22 | echo Provision complete.
23 |
--------------------------------------------------------------------------------