001/**
002 * Copyright 2015 DuraSpace, Inc.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.fcrepo.client.impl;
017
018import static com.hp.hpl.jena.graph.NodeFactory.createLiteral;
019import static com.hp.hpl.jena.graph.NodeFactory.createURI;
020import static org.apache.http.HttpStatus.SC_CREATED;
021import static org.apache.http.HttpStatus.SC_NOT_FOUND;
022import static org.apache.http.HttpStatus.SC_OK;
023import static org.fcrepo.kernel.api.RdfLexicon.HAS_PRIMARY_IDENTIFIER;
024import static org.junit.Assert.assertEquals;
025import static org.junit.Assert.assertFalse;
026import static org.junit.Assert.assertNotNull;
027import static org.junit.Assert.assertTrue;
028import static org.mockito.Matchers.any;
029import static org.mockito.Matchers.anyString;
030import static org.mockito.Matchers.eq;
031import static org.mockito.Mockito.doReturn;
032import static org.mockito.Mockito.doThrow;
033import static org.mockito.Mockito.mock;
034import static org.mockito.Mockito.spy;
035import static org.mockito.Mockito.when;
036import static org.mockito.MockitoAnnotations.initMocks;
037
038import java.io.ByteArrayInputStream;
039import java.io.IOException;
040import java.io.InputStream;
041import java.net.URI;
042
043import org.fcrepo.client.NotFoundException;
044
045import com.hp.hpl.jena.graph.Graph;
046import org.apache.http.Header;
047import org.apache.http.HttpEntity;
048import org.apache.http.HttpResponse;
049import org.apache.http.StatusLine;
050import org.apache.http.client.HttpClient;
051import org.apache.http.client.methods.HttpUriRequest;
052import org.apache.http.client.methods.HttpPut;
053import org.fcrepo.client.FedoraContent;
054import org.fcrepo.client.FedoraException;
055import org.fcrepo.client.FedoraObject;
056import org.fcrepo.client.utils.HttpHelper;
057import org.junit.Before;
058import org.junit.Test;
059import org.mockito.Mock;
060
061/**
062 * Writable repository impl -- read and write operations should both work.
063 *
064 * @author lsitu
065 * @author escowles
066 *
067 */
068public class FedoraRepositoryImplTest {
069
070    FedoraRepositoryImpl fedoraRepository;
071    HttpHelper httpHelper;
072
073    @Mock
074    HttpClient mockClient;
075
076    @Mock
077    private HttpResponse mockResponse;
078
079    @Mock
080    private HttpEntity mockEntity;
081
082    @Mock
083    private StatusLine mockStatusLine;
084
085    @Mock
086    private FedoraObjectImpl mockObject;
087
088    String testRepositoryUrl = "http://localhost:8080/rest";
089
090    private final String testContent = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
091                "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"" +
092                " xmlns:fcrepo=\"http://fedora.info/definitions/v4/repository#\">" +
093                "<rdf:Description rdf:about=\"http://localhost:8080/rest/testObject\">" +
094                "<rdf:type rdf:resource=\"http://fedora.info/definitions/v4/rest-api#resource\"/>" +
095                "<rdf:type rdf:resource=\"http://fedora.info/definitions/v4/rest-api#object\"/>" +
096                "<fcrepo:uuid>2fb9c440-db63-434f-929b-0ff29253205c</fcrepo:uuid>" +
097                "</rdf:Description>" +
098                "</rdf:RDF>";
099
100
101    @Before
102    public void setUp() throws IOException {
103        initMocks(this);
104        fedoraRepository = new FedoraRepositoryImpl (testRepositoryUrl, mockClient);
105        httpHelper = new HttpHelper( testRepositoryUrl, mockClient, false );
106    }
107
108    @Test
109    public void testGetObject() throws IOException, FedoraException {
110        final String testId = "testGetObject";
111        when(mockClient.execute(any(HttpUriRequest.class))).thenReturn(mockResponse);
112        when(mockResponse.getEntity()).thenReturn(mockEntity);
113        final Header mockContentType = mock(Header.class);
114        when(mockEntity.getContentType()).thenReturn(mockContentType);
115        when(mockContentType.getValue()).thenReturn("application/rdf+xml");
116        when(mockResponse.getStatusLine()).thenReturn(mockStatusLine);
117        when(mockStatusLine.getStatusCode()).thenReturn(SC_OK);
118        try (
119            InputStream rdf =
120                new ByteArrayInputStream(testContent.getBytes())) {
121            when(mockEntity.getContent()).thenReturn(rdf);
122        }
123        final FedoraObject testObject = fedoraRepository.getObject(testId);
124        assertNotNull(testObject);
125        assertTrue(testObject.getProperties().hasNext());
126    }
127
128    @Test
129    public void testGetRepositoryUrl() {
130        assertEquals ("Resitory URL is not the same", testRepositoryUrl, fedoraRepository.getRepositoryUrl());
131    }
132
133    @Test
134    public void testExists() throws IOException, FedoraException {
135        final String testId = "testGetObject";
136        when(mockClient.execute(any(HttpUriRequest.class))).thenReturn(mockResponse);
137        when(mockResponse.getStatusLine()).thenReturn(mockStatusLine);
138        when(mockStatusLine.getStatusCode()).thenReturn(SC_OK);
139        assertTrue(fedoraRepository.exists(testId));
140    }
141
142    @Test
143    public void testExistsNonExistent() throws IOException, FedoraException {
144        final String testId = "testNonExistent";
145        when(mockClient.execute(any(HttpUriRequest.class))).thenReturn(mockResponse);
146        when(mockResponse.getStatusLine()).thenReturn(mockStatusLine);
147        when(mockStatusLine.getStatusCode()).thenReturn(SC_NOT_FOUND);
148        assertFalse(fedoraRepository.exists(testId));
149    }
150
151    @Test
152    public void testCreateObject() throws IOException, FedoraException {
153        final String testId = "testNewObject";
154        final HttpResponse mockResponse2 = mock(HttpResponse.class);
155        final StatusLine mockStatusLine2 = mock(StatusLine.class);
156
157        when(mockClient.execute(any(HttpUriRequest.class))).thenReturn(mockResponse2,mockResponse);
158
159        // put
160        when(mockResponse2.getStatusLine()).thenReturn(mockStatusLine2);
161        when(mockStatusLine2.getStatusCode()).thenReturn(SC_CREATED);
162        when(mockStatusLine2.getReasonPhrase()).thenReturn("Created");
163
164        // get
165        when(mockResponse.getEntity()).thenReturn(mockEntity);
166        final Header mockContentType = mock(Header.class);
167        when(mockEntity.getContentType()).thenReturn(mockContentType);
168        when(mockContentType.getValue()).thenReturn("application/rdf+xml");
169        when(mockResponse.getStatusLine()).thenReturn(mockStatusLine);
170        when(mockStatusLine.getStatusCode()).thenReturn(SC_OK);
171        when(mockStatusLine.getReasonPhrase()).thenReturn("OK");
172        try (
173            InputStream rdf =
174                new ByteArrayInputStream(testContent.getBytes())) {
175            when(mockEntity.getContent()).thenReturn(rdf);
176        }
177
178        final FedoraObject testObject = fedoraRepository.createObject(testId);
179        assertNotNull(testObject);
180        assertTrue(testObject.getProperties().hasNext());
181    }
182
183    @Test
184    public void testFindOrCreateObject() throws FedoraException {
185        final FedoraRepositoryImpl spy = spy( new FedoraRepositoryImpl(testRepositoryUrl, mockClient) );
186        final FedoraObject mockObject = mock(FedoraObject.class);
187        doReturn(mockObject).when(spy).getObject(anyString());
188
189        final FedoraObject object = spy.findOrCreateObject("/foo");
190        assertEquals(mockObject, object);
191    }
192
193    @Test
194    public void testFindOrCreateObjectNonExistent() throws FedoraException {
195        final FedoraRepositoryImpl spy = spy( new FedoraRepositoryImpl(testRepositoryUrl, mockClient) );
196        final NotFoundException mockException = mock(NotFoundException.class);
197        doThrow(mockException).when(spy).getObject(anyString());
198        final FedoraObject mockObject = mock(FedoraObject.class);
199        doReturn(mockObject).when(spy).createObject(anyString());
200
201        final FedoraObject object = spy.findOrCreateObject("/foo");
202        assertEquals(mockObject, object);
203    }
204
205    @Test
206    public void testWritable() {
207        assertTrue( fedoraRepository.isWritable() );
208    }
209
210    @Test
211    public void testUpdateProperties() throws Exception {
212        final String path = "/testObject";
213        final String etag = "urn:sha1:e242ed3bffccdf271b7fbaf34ed72d089537b42f";
214        final URI uri = new URI( testRepositoryUrl + path );
215        final HttpResponse response = mock(HttpResponse.class);
216        final StatusLine status = mock(StatusLine.class);
217        final FedoraObjectImpl object = new FedoraObjectImpl( fedoraRepository, httpHelper, path );
218        final Header etagHeader = mock(Header.class);
219        final Header[] etagArray = new Header[]{ etagHeader };
220        final Header typeHeader = mock(Header.class);
221        final HttpEntity entity = mock(HttpEntity.class);
222
223        when(mockClient.execute(any(HttpUriRequest.class))).thenReturn(response);
224        when(response.getStatusLine()).thenReturn(status);
225        when(status.getStatusCode()).thenReturn(200);
226        when(response.getHeaders(eq("ETag"))).thenReturn(etagArray);
227        when(response.getEntity()).thenReturn(entity);
228        when(entity.getContentType()).thenReturn(typeHeader);
229        when(etagHeader.getValue()).thenReturn(etag);
230        when(typeHeader.getValue()).thenReturn("application/rdf+xml");
231        when(entity.getContent()).thenReturn(new ByteArrayInputStream(testContent.getBytes()));
232
233        httpHelper.loadProperties( object );
234        final Graph g = object.getGraph();
235        assertNotNull(g);
236        assertTrue( g.contains( createURI(uri.toString()), HAS_PRIMARY_IDENTIFIER.asNode(),
237            createLiteral("2fb9c440-db63-434f-929b-0ff29253205c")) );
238    }
239
240    @Test
241    public void testCreateContentPutMethod() throws Exception {
242        final String path = "/test";
243        final InputStream in = new ByteArrayInputStream( "foo".getBytes() );
244        final String mime = "image/jpeg";
245        final String fn = "image.jpg";
246        final String chk = "urn:sha1:c6bbf022f8f19d09106622aa912218417723f543";
247        final URI checksumURI = new URI(chk);
248        final FedoraContent cont = new FedoraContent().setContent(in).setContentType(mime)
249                                                      .setFilename(fn).setChecksum(checksumURI);
250
251        final HttpPut put = httpHelper.createContentPutMethod(path, null, cont);
252
253        assertEquals( testRepositoryUrl + path + "?checksum=" + chk, put.getURI().toString() );
254        assertEquals( in, put.getEntity().getContent() );
255        assertEquals( mime, put.getFirstHeader("Content-Type").getValue() );
256        assertEquals( "attachment; filename=\"" + fn + "\"", put.getFirstHeader("Content-Disposition").getValue() );
257    }
258}