001    package org.hackystat.sensorbase.resource.projects;
002    
003    import static org.hackystat.sensorbase.server.ServerProperties.TEST_DOMAIN_KEY;
004    import static org.junit.Assert.assertEquals;
005    import static org.junit.Assert.assertFalse;
006    import static org.junit.Assert.assertTrue;
007    
008    import javax.xml.datatype.XMLGregorianCalendar;
009    import org.hackystat.sensorbase.client.SensorBaseClient;
010    import org.hackystat.sensorbase.client.SensorBaseClientException;
011    import org.hackystat.sensorbase.resource.projects.jaxb.MultiDayProjectSummary;
012    import org.hackystat.sensorbase.resource.projects.jaxb.Project;
013    import org.hackystat.sensorbase.resource.projects.jaxb.ProjectIndex;
014    import org.hackystat.sensorbase.resource.projects.jaxb.ProjectRef;
015    import org.hackystat.sensorbase.resource.projects.jaxb.ProjectSummary;
016    import org.hackystat.sensorbase.resource.projects.jaxb.SensorDataSummary;
017    import org.hackystat.sensorbase.resource.projects.jaxb.UriPatterns;
018    import org.hackystat.sensorbase.resource.sensordata.jaxb.SensorData;
019    import org.hackystat.sensorbase.resource.sensordata.jaxb.SensorDataIndex;
020    import org.hackystat.sensorbase.test.SensorBaseRestApiHelper;
021    import org.hackystat.utilities.tstamp.Tstamp;
022    import org.junit.Test;
023    
024    /**
025     * Tests the SensorBase REST API for Project resources.
026     * 
027     * @author Philip M. Johnson
028     */
029    public class TestProjectRestApi extends SensorBaseRestApiHelper {
030    
031      private String testUser = "TestUser@hackystat.org";
032      private String testProject = "TestProject";
033      private String testSdt = "TestSdt";
034      private String defaultProject = "Default";
035      private static final String nineAm = "2007-04-30T09:00:00.000";
036    
037      /**
038       * Test that GET host/sensorbase/projects returns an index containing at least one Project. This
039       * is an admin-only request. Probably want to (at)ignore this method on real distributions, 
040       * since the returned dataset could be large.
041       * @throws Exception If problems occur.
042       */
043      @Test
044      public void getProjectIndex() throws Exception {
045        // Create an admin client and check authentication.
046        SensorBaseClient client = new SensorBaseClient(getHostName(), adminEmail, adminPassword);
047        client.authenticate();
048        // Get the index of all Projects.
049        ProjectIndex index = client.getProjectIndex();
050        // Make sure that we can iterate through the data and dereference all hrefs.
051        for (ProjectRef ref : index.getProjectRef()) {
052          client.getProject(ref);
053        }
054        assertTrue("Checking for project data", index.getProjectRef().size() > 1);
055      }
056    
057      /**
058       * Test that GET host/sensorbase/projects/TestUser@hackystat.org returns an index containing at
059       * least one ProjectRef.
060       * 
061       * @throws Exception If problems occur.
062       */
063      @Test
064      public void getTestUserProjectIndex() throws Exception {
065        // Create the TestUser client and check authentication.
066        SensorBaseClient client = new SensorBaseClient(getHostName(), testUser, testUser);
067        client.authenticate();
068        // Get the index of this user's Projects.
069        ProjectIndex index = client.getProjectIndex(testUser);
070        // Make sure that we can iterate through the data and dereference all hrefs.
071        for (ProjectRef ref : index.getProjectRef()) {
072          client.getUri(ref.getHref());
073        }
074        assertTrue("Checking for project data", index.getProjectRef().size() > 1);
075      }
076    
077      /**
078       * Test that GET host/sensorbase/projects/TestUser@hackystat.org/TestProject returns a
079       * representation of TestProject.
080       * 
081       * @throws Exception If problems occur.
082       */
083      @Test
084      public void getTestUserProject() throws Exception {
085        // Create the TestUser client and check authentication.
086        SensorBaseClient client = new SensorBaseClient(getHostName(), testUser, testUser);
087        client.authenticate();
088        // Retrieve the TestProject project and test a field.
089        Project project = client.getProject(testUser, testProject);
090        assertEquals("Checking project name", testProject, project.getName());
091      }
092    
093      /**
094       * Test that GET host/sensorbase/projects/TestUser@hackystat.org/TestProject/sensordata returns an
095       * index of SensorData.
096       * 
097       * @throws Exception If problems occur.
098       */
099      @Test
100      public void getTestUserProjectSensorData() throws Exception {
101        // Create the TestUser client and check authentication.
102        SensorBaseClient client = new SensorBaseClient(getHostName(), testUser, testUser);
103        client.authenticate();
104        // Retrieve the SensorData for the TestProject project and test a couple of
105        // fields.
106        SensorDataIndex index = client.getProjectSensorData(testUser, testProject);
107        assertTrue("Checking index has entries", index.getSensorDataRef().size() > 1);
108      }
109    
110      /**
111       * Test that GET host/sensorbase/projects/TestUser@hackystat.org/TestProject/sensordata?
112       * startTime=2006-04-30T09:00:00.000&endTime=2007-04-30T09:30:00.000 returns an index of
113       * SensorData containing one entry.
114       * 
115       * @throws Exception If problems occur.
116       */
117      @Test
118      public void getTestUserProjectSensorSummary() throws Exception {
119        // Create the TestUser client and check authentication.
120        SensorBaseClient client = new SensorBaseClient(getHostName(), testUser, testUser);
121        client.authenticate();
122        // Retrieve the SensorData for the TestProject project within the time
123        // interval.
124        XMLGregorianCalendar startTime = Tstamp.makeTimestamp(nineAm);
125        XMLGregorianCalendar endTime = Tstamp.makeTimestamp("2007-04-30T09:30:00.000");
126        ProjectSummary summary = client.getProjectSummary(testUser, testProject, startTime, endTime);
127        assertEquals("Checking summary size", 1, 
128            summary.getSensorDataSummaries().getNumInstances().intValue());
129        SensorDataSummary dataSummary = summary.getSensorDataSummaries().getSensorDataSummary().get(0);
130        assertEquals("Checking summary tool", "Subversion", dataSummary.getTool());
131        assertEquals("Checking summary type", testSdt, dataSummary.getSensorDataType());
132        assertEquals("Checking summary instances", 1, dataSummary.getNumInstances().intValue());
133        // Now try for multiple days.
134        MultiDayProjectSummary multiSummary = client.getMultiDayProjectSummary(testUser, testProject, 
135            startTime, 3);
136        assertEquals("Checking MultiDayProjectSummary", 3, multiSummary.getProjectSummary().size());
137      }
138      
139      /**
140       * Tests the snapshot API.
141       * @throws Exception If problems occur.
142       */
143      @Test
144      public void getTestUserProjectSnapshot() throws Exception {
145        // Create the TestUser client and check authentication.
146        String snapshotUser = "TestProjectSnapshot@hackystat.org";
147        SensorBaseClient.registerUser(getHostName(), snapshotUser);
148        SensorBaseClient client = new SensorBaseClient(getHostName(), snapshotUser, snapshotUser);
149        client.authenticate();
150        // The time interval we'll work in. These will also be our runtimes.
151        XMLGregorianCalendar startTime = Tstamp.makeTimestamp(nineAm);
152        XMLGregorianCalendar endTime = Tstamp.makeTimestamp("2007-04-30T09:30:00.000");
153    
154        XMLGregorianCalendar tstamp1 = Tstamp.incrementMinutes(startTime, 1);
155        XMLGregorianCalendar tstamp2 = Tstamp.incrementMinutes(startTime, 2);
156        XMLGregorianCalendar tstamp3 = Tstamp.incrementMinutes(startTime, 3);
157        String sdt = testSdt;
158        String tool1 = "Tool1";
159        String tool2 = "Tool2";
160        client.putSensorData(makeSensorData(tstamp1, tstamp1, snapshotUser, sdt, tool1));
161        client.putSensorData(makeSensorData(tstamp2, tstamp1, snapshotUser, sdt, tool1));
162        client.putSensorData(makeSensorData(tstamp3, tstamp3, snapshotUser, sdt, tool2));
163    
164        // We should get the last sensor data item.
165        SensorDataIndex snap1 = 
166          client.getProjectSensorDataSnapshot(snapshotUser, defaultProject, startTime, endTime, sdt);
167        assertEquals("Checking snap1 size", 1, snap1.getSensorDataRef().size()); 
168        assertEquals("Checking snap1 tstamp", tstamp3, snap1.getSensorDataRef().get(0).getTimestamp());
169        
170        // Now check that we get the other two when we specify the tool.
171        SensorDataIndex snap2 = 
172          client.getProjectSensorDataSnapshot(snapshotUser, defaultProject, startTime, endTime, sdt, 
173              tool1);
174        assertEquals("Checking snap2 size", 2, snap2.getSensorDataRef().size()); 
175      }
176      
177      /**
178       * Creates a sample SensorData instance for use in testing snapshots. 
179       * @param tstamp The timestamp.
180       * @param runtime The runtime
181       * @param user The user.
182       * @param sdt The sensor data type.
183       * @param tool The tool.
184       * @return The new SensorData instance. 
185       */
186      private SensorData makeSensorData(XMLGregorianCalendar tstamp, XMLGregorianCalendar runtime,
187          String user, String sdt, String tool) {
188        SensorData data = new SensorData();
189        data.setTool(tool);
190        data.setOwner(user);
191        data.setSensorDataType(sdt);
192        data.setTimestamp(tstamp);
193        data.setResource("file://foo/bar/baz.txt");
194        data.setRuntime(runtime);
195        return data;
196      }
197      
198      /**
199       * Test that GET host/sensorbase/projects/TestUser@hackystat.org/TestProject/sensordata?
200       * startTime=2006-04-30T09:00:00.000&endTime=2007-04-30T09:30:00.000 returns an index of
201       * SensorData containing one entry.
202       * 
203       * @throws Exception If problems occur.
204       */
205      @Test
206      public void getTestUserProjectSensorDataInterval() throws Exception {
207        // Create the TestUser client and check authentication.
208        SensorBaseClient client = new SensorBaseClient(getHostName(), testUser, testUser);
209        client.authenticate();
210        // Retrieve the SensorData for the TestProject project within the time
211        // interval.
212        XMLGregorianCalendar startTime = Tstamp.makeTimestamp(nineAm);
213        XMLGregorianCalendar endTime = Tstamp.makeTimestamp("2007-04-30T09:30:00.000");
214        SensorDataIndex index = client.getProjectSensorData(testUser, testProject, startTime, endTime);
215        assertEquals("Checking index contains one entry", 1, index.getSensorDataRef().size());
216      }
217      
218      /**
219       * Test that the GET of a project with the SDT parameter works correctly.
220       * Assumes that the default XML data files are loaded, which result in two sensor data entries
221       * for TestUser@hackystat.org on 2007-04-30, one with SDT=TestSdt and one with SDT=SampleSdt.
222       * 
223       * @throws Exception If problems occur.
224       */
225      @Test
226      public void getTestUserProjectSdtParam() throws Exception {
227        // Create the TestUser client and check authentication.
228        SensorBaseClient client = new SensorBaseClient(getHostName(), testUser, testUser);
229        client.authenticate();
230        // Retrieve the SensorData for the TestProject project within the time
231        // interval, and make sure we have the two entries that we expect. 
232        XMLGregorianCalendar startTime = Tstamp.makeTimestamp(nineAm);
233        XMLGregorianCalendar endTime = Tstamp.makeTimestamp("2007-04-30T10:00:00.000");
234        SensorDataIndex index = client.getProjectSensorData(testUser, testProject, startTime, endTime);
235        assertEquals("Checking our test data has 2 entries", 2, index.getSensorDataRef().size());
236        
237        // Now test the SDT param call to make sure we get only the SDT of interest.
238        index = client.getProjectSensorData(testUser, testProject, startTime, endTime, testSdt);
239        assertEquals("Checking our test data has 1 entries", 1, index.getSensorDataRef().size());
240        
241        // Now test to see that the tool param works correctly. 
242        index = client.getProjectSensorData(testUser, testProject, startTime, endTime, testSdt, 
243        "Subversion");
244        assertEquals("Checking our data has 1 entries", 1, index.getSensorDataRef().size());
245        index = client.getProjectSensorData(testUser, testProject, startTime, endTime, testSdt, 
246        "CVS");
247        assertEquals("Checking our data has no entries", 0, index.getSensorDataRef().size());
248      }
249      
250      
251      /**
252       * Test that the GET of a project with the startIndex/maxInstances parameters work correctly.
253       * Assumes that the default XML data files are loaded, which result in two sensor data entries
254       * for TestUser@hackystat.org on 2007-04-30, one with SDT=TestSdt and one with SDT=SampleSdt.
255       * We'll try a few combinations of startIndex and maxInstances to see that the proper number
256       * of instances are returned.
257       * 
258       * @throws Exception If problems occur.
259       */
260      @Test
261      public void getTestUserProjectStartIndexMaxInstancesParams() throws Exception {
262        // Create the TestUser client and check authentication.
263        SensorBaseClient client = new SensorBaseClient(getHostName(), testUser, testUser);
264        client.authenticate();
265        // Retrieve the SensorData for the TestProject project within the time
266        // interval, and make sure we have the two entries that we expect. 
267        XMLGregorianCalendar startTime = Tstamp.makeTimestamp(nineAm);
268        XMLGregorianCalendar endTime = Tstamp.makeTimestamp("2007-04-30T10:00:00.000");
269        SensorDataIndex index = client.getProjectSensorData(testUser, testProject, startTime, endTime);
270        assertEquals("Checking our original data has 2 entries", 2, index.getSensorDataRef().size());
271        
272        // Now test the startIndex/maxInstances params.
273        index = client.getProjectSensorData(testUser, testProject, startTime, endTime, 0, 100);
274        assertEquals("Checking startindex 1 is 2", 2, index.getSensorDataRef().size());
275    
276        index = client.getProjectSensorData(testUser, testProject, startTime, endTime, 1, 100);
277        assertEquals("Checking startindex 2 is 1", 1, index.getSensorDataRef().size());
278    
279        index = client.getProjectSensorData(testUser, testProject, startTime, endTime, 0, 1);
280        assertEquals("Checking startindex 3 is 1", 1, index.getSensorDataRef().size());
281    
282        index = client.getProjectSensorData(testUser, testProject, startTime, endTime, 1, 1);
283        assertEquals("Checking startindex 4 is 1", 1, index.getSensorDataRef().size());
284        
285        index = client.getProjectSensorData(testUser, testProject, startTime, endTime, 2, 1);
286        assertEquals("Checking startindex 5 is 0", 0, index.getSensorDataRef().size());
287    
288    
289      }
290    
291      /**
292       * Test that PUT, rename, and DELETE of host/projects/{user}/{project} works.
293       * 
294       * @throws Exception If problems occur.
295       */
296      @Test
297      public void putProject() throws Exception {
298        // First, create a sample Project.
299        String owner = testUser;
300        String projectName = "TestProject1";
301        Project project = new Project();
302        project.setOwner(owner);
303        project.setName(projectName);
304        project.setDescription("Test Project1");
305        XMLGregorianCalendar tstamp = Tstamp.makeTimestamp();
306        project.setStartTime(tstamp);
307        project.setEndTime(tstamp);
308        UriPatterns uris = new UriPatterns();
309        uris.getUriPattern().add("**/test/**");
310        project.setUriPatterns(uris);
311    
312        // Create the TestUser client, check authentication, and post the Project to
313        // the server.
314        SensorBaseClient client = new SensorBaseClient(getHostName(), testUser, testUser);
315        client.authenticate();
316        client.putProject(project);
317    
318        // Check that we can now retrieve it.
319        Project project2 = client.getProject(owner, projectName);
320        assertEquals("Testing for GET TestProject1", projectName, project2.getName());
321        
322        // Check that we can now rename it. 
323        String newProjectName = "NewTestProjectName";
324        client.renameProject(owner, projectName, newProjectName);
325        ProjectIndex index = client.getProjectIndex(testUser);
326        assertTrue("Checking renamed project is in index", hasProjectName(index, newProjectName));
327        assertFalse("Checking old project name is not in index", hasProjectName(index, projectName));
328    
329        // Test that DELETE gets rid of this Project.
330        client.deleteProject(owner, newProjectName);
331      }
332    
333      /**
334       * Returns true if the passed projectName is in the ProjectIndex.
335       * @param index The ProjectIndex. 
336       * @param projectName The projectname of interest. 
337       * @return True if the projectName is in the index. 
338       */
339      private boolean hasProjectName(ProjectIndex index, String projectName) {
340        for (ProjectRef ref : index.getProjectRef()) {
341          if (ref.getName().equals(projectName)) {
342            return true;
343          }
344        }
345        return false;
346      }
347      
348      /**
349       * A helper method to detect HTTP 400 status return values. 
350       * Because of intermittent 1001 errors in the sensorbase test suite, this method
351       * will also return true if a 1001 error is returned. 
352       * @param e The exception 
353       * @return True if the exception message starts with 400 (or 1001).
354       */
355      private boolean is400(Exception e) {
356        return (e.getMessage().startsWith("400") || e.getMessage().startsWith("1001"));
357        
358      }
359      
360      /**
361       * Test that PUT of incomplete project definitions causes errors. 
362       * 
363       * @throws Exception If problems occur.
364       */
365      @Test
366      public void putBadProjects() throws Exception {
367        // Create the TestUser client, check authentication.
368        SensorBaseClient client = new SensorBaseClient(getHostName(), testUser, testUser);
369        client.authenticate();
370        
371        // First, create a sample Project with no fields.
372        Project project = new Project();
373        String owner = testUser;
374        project.setOwner(owner);
375        // See if we get the appropriate error
376        try {
377          client.putProject(project);
378        }
379        catch (SensorBaseClientException e) {
380          assertTrue("Test bad project name", is400(e));
381        }
382        // Fix the project name, try again.    
383        String projectName = "TestProject1";
384        project.setName(projectName);
385        try {
386          client.putProject(project);
387        }
388        catch (SensorBaseClientException e) {
389          assertTrue("Test bad start", is400(e));
390        }
391        XMLGregorianCalendar tstamp = Tstamp.makeTimestamp();
392        project.setStartTime(tstamp);
393        
394        try {
395          client.putProject(project);
396        }
397        catch (SensorBaseClientException e) {
398          assertTrue("Test bad end", is400(e));
399        }
400        project.setEndTime(tstamp);
401        // Now this should succeed.
402        client.putProject(project);
403    
404        // Check that we can now retrieve it.
405        Project project2 = client.getProject(owner, projectName);
406        assertEquals("Testing for GET TestProject1", projectName, project2.getName());
407    
408        // Test that DELETE gets rid of this Project.
409        client.deleteProject(owner, projectName);
410      }
411    
412      /**
413       * Test that PUT multiple times does not cause a problem for getProjectIndex.
414       * 
415       * @throws Exception If problems occur.
416       */
417      //@Ignore
418      @Test
419      public void putMultipleProject() throws Exception {
420        // First, create a sample Project.
421        String owner = testUser;
422        String projectName = "TestProject1";
423        Project project = new Project();
424        project.setOwner(owner);
425        project.setName(projectName);
426        project.setDescription("Test Project1");
427        XMLGregorianCalendar tstamp = Tstamp.makeTimestamp();
428        project.setStartTime(tstamp);
429        project.setEndTime(tstamp);
430        UriPatterns uris = new UriPatterns();
431        uris.getUriPattern().add("**/test/**");
432        project.setUriPatterns(uris);
433    
434        // Create the TestUser client.
435        SensorBaseClient client = new SensorBaseClient(getHostName(), adminEmail, adminPassword);
436        client.authenticate();
437        // Now add a project.
438        client.putProject(project);
439        // Get the size after adding.
440        int before = client.getProjectIndex().getProjectRef().size();
441        // Now add it again.
442        client.putProject(project);
443        // Get the size after adding.
444        int after = client.getProjectIndex().getProjectRef().size();
445        // Check that the size hasn't changed.
446        assertEquals("Checking ProjectIndex after adding duplicate Project", before, after);
447      }
448      
449    
450    
451      /**
452       * Tests that after creating a new User, it has a Default Project.
453       * 
454       * @throws Exception If problems occur.
455       */
456      @Test
457      public void newUserTest() throws Exception {
458        // Register a new user.
459        String newUser = "NewUserTest@" + server.getServerProperties().get(TEST_DOMAIN_KEY);
460        SensorBaseClient.registerUser(getHostName(), newUser);
461        // Create a Client for this new user.
462        SensorBaseClient client = new SensorBaseClient(getHostName(), newUser, newUser);
463        client.authenticate();
464    
465        Project project = client.getProject(newUser, defaultProject);
466        assertEquals("Checking default project", defaultProject, project.getName());
467    
468        // Now we delete the user
469        client.deleteUser(newUser);
470      }
471    
472      /**
473       * Tests that we can retrieve all data for the TestUser under their Default Project.
474       * 
475       * @throws Exception If problems occur.
476       */
477      @Test
478      public void testUserDefaultProjectData() throws Exception {
479        SensorBaseClient client = new SensorBaseClient(getHostName(), testUser, testUser);
480        client.authenticate();
481    
482        SensorDataIndex index = client.getProjectSensorData(testUser, defaultProject);
483        assertTrue("Checking for testuser sensordata", index.getSensorDataRef().size() >= 3);
484      }
485    }