/**
   * Tests getting the project's collections
   *
   * @throws InvalidXmlException
   * @throws BizInternalException
   * @throws BizPolicyException
   * @throws IOException
   */
  @Test
  public void testGetProjectsCollections()
      throws InvalidXmlException, BizInternalException, BizPolicyException, IOException {

    final String mimeType = "application/xml";
    final MockHttpServletRequest mockReq =
        newMockRequest("GET", projectOne.getId() + "/collections", "test.org", 80);
    MockHttpServletResponse resp = new MockHttpServletResponse();

    when(requestUtil.buildRequestUrl(any(HttpServletRequest.class)))
        .thenReturn(projectOne.getId() + "/collections");

    controller.setAuthenticatedUser(admin);
    controller.handleProjectCollectionsGetRequest(
        projectOne.getId(), mimeType, null, mockReq, resp);

    assertNotNull(resp);
    assertEquals(resp.getErrorMessage(), 200, resp.getStatus());
    Bop returnedBop =
        businessObjectBuilder.buildBusinessObjectPackage(
            new ByteArrayInputStream(resp.getContentAsByteArray()));
    assertNotNull(returnedBop);

    Set<Collection> collections = returnedBop.getCollections();
    assertNotNull(collections);
    assertEquals(1, collections.size());
  }
  /**
   * Test getting a project that does not exist
   *
   * @throws InvalidXmlException
   * @throws BizInternalException
   * @throws BizPolicyException
   * @throws IOException
   */
  @Test
  public void testGetNonExistingProject()
      throws InvalidXmlException, BizInternalException, BizPolicyException, IOException {

    when(requestUtil.buildRequestUrl(any(HttpServletRequest.class))).thenReturn("  ");

    final String mimeType = "application/xml";
    final MockHttpServletRequest mockReq =
        newMockRequest("GET", "/project/" + "cowsarethebest", "test.org", 80);
    MockHttpServletResponse resp = new MockHttpServletResponse();

    controller.setAuthenticatedUser(admin);
    controller.handleProjectGetRequest(projectOne.getId(), mimeType, null, mockReq, resp);

    assertNotNull(resp);
    assertEquals(404, resp.getStatus());
  }
  /**
   * Tests adding a project through the API
   *
   * @throws InvalidXmlException
   * @throws BizInternalException
   * @throws BizPolicyException
   * @throws IOException
   */
  @Test
  public void testAddProject()
      throws InvalidXmlException, BizInternalException, BizPolicyException, IOException {
    Project newProject = new Project();
    newProject.setName("Test Project To Add");
    newProject.setDescription("adding this project");
    List<String> numbers = new ArrayList<String>();
    numbers.add("1");
    numbers.add("2");
    newProject.setNumbers(numbers);
    newProject.setFundingEntity("The Fed");
    newProject.setStartDate(new DateTime(2012, 5, 4, 0, 0));
    newProject.setEndDate(new DateTime(2013, 12, 23, 0, 0));
    newProject.addPi(admin.getId());

    final String mimeType = "application/xml";
    final MockHttpServletRequest mockReq = newMockRequest("POST", "/project", "test.org", 80);
    MockHttpServletResponse resp = new MockHttpServletResponse();

    ByteArrayOutputStream sink = new ByteArrayOutputStream();
    businessObjectBuilder.buildProject(newProject, sink);

    controller.setAuthenticatedUser(admin);
    controller.handleProjectPostRequest(mimeType, sink.toByteArray(), mockReq, resp);

    assertNotNull(resp);

    assertEquals(201, resp.getStatus());
    Bop bop =
        businessObjectBuilder.buildBusinessObjectPackage(
            new ByteArrayInputStream(resp.getContentAsByteArray()));

    assertNotNull(bop);

    Set<Project> projects = bop.getProjects();
    assertNotNull(projects);
    assertEquals(1, projects.size());

    Project returnedProject = projects.iterator().next();

    // Have to set the original project id to the id set by the biz service.
    newProject.setId(returnedProject.getId());
    assertEquals(newProject, returnedProject);
  }
  /**
   * Tests that the project metadata is successfully updated.
   *
   * @throws InvalidXmlException
   * @throws ProjectServiceException
   * @throws BizPolicyException
   * @throws IOException
   */
  @Test
  public void testUpdateProject()
      throws InvalidXmlException, BizInternalException, BizPolicyException, IOException {

    Project newProject = new Project(projectOne);
    newProject.setName("Update");
    newProject.setDescription("foo-update");
    newProject.setEndDate(new DateTime(2014, 2, 10, 0, 0));

    final String mimeType = "application/xml";
    final MockHttpServletRequest mockReq =
        newMockRequest("PUT", projectOne.getId(), "test.org", 80);
    MockHttpServletResponse resp = new MockHttpServletResponse();

    ByteArrayOutputStream sink = new ByteArrayOutputStream();
    businessObjectBuilder.buildProject(newProject, sink);

    controller.setAuthenticatedUser(admin);
    controller.handleUpdateProjectRequest(
        projectOne.getId(), mimeType, sink.toByteArray(), mockReq, resp);

    assertNotNull(resp);
    assertEquals(resp.getErrorMessage(), 200, resp.getStatus());

    Bop bop =
        businessObjectBuilder.buildBusinessObjectPackage(
            new ByteArrayInputStream(resp.getContentAsByteArray()));

    assertNotNull(bop);

    Set<Project> projects = bop.getProjects();
    assertNotNull(projects);
    assertEquals(1, projects.size());

    Project returnedProject = projects.iterator().next();
    assertNotNull(returnedProject);

    assertTrue(returnedProject.getName().equalsIgnoreCase(newProject.getName()));
    assertTrue(returnedProject.getDescription().equalsIgnoreCase(newProject.getDescription()));
    assertTrue(returnedProject.getEndDate().equals(newProject.getEndDate()));

    assertTrue(returnedProject.getFundingEntity().equalsIgnoreCase(newProject.getFundingEntity()));
  }
 public ProjectManagementPage(SectionView parent) {
   super(parent, "Projects");
   controller.addListener(
       new Listener<ProjectEvent>() {
         @Override
         public void handleEvent(ProjectEvent event) {
           if (view != null) {
             view.refresh();
           }
         }
       });
 }
  /**
   * Test getting a project
   *
   * @throws InvalidXmlException
   * @throws BizInternalException
   * @throws BizPolicyException
   * @throws IOException
   */
  @Test
  public void testGetProject()
      throws InvalidXmlException, BizInternalException, BizPolicyException, IOException {

    final String mimeType = "application/xml";
    final MockHttpServletRequest mockReq =
        newMockRequest("GET", projectOne.getId(), "test.org", 80);
    MockHttpServletResponse resp = new MockHttpServletResponse();

    controller.setAuthenticatedUser(admin);
    controller.handleProjectGetRequest(projectOne.getId(), mimeType, null, mockReq, resp);

    assertNotNull(resp);
    assertEquals(resp.getErrorMessage(), 200, resp.getStatus());
    Bop bop =
        businessObjectBuilder.buildBusinessObjectPackage(
            new ByteArrayInputStream(resp.getContentAsByteArray()));
    assertNotNull(bop);
    assertEquals(1, bop.getProjects().size());
    assertEquals(projectOne, bop.getProjects().iterator().next());
  }
    @Override
    public void editItem(Object[] items) {
      try {
        String projName = (String) items[0];
        int projID =
            MedSavantClient.ProjectManager.getProjectID(
                LoginController.getInstance().getSessionID(), projName);

        // Check for existing unpublished changes to this project.
        if (ProjectController.getInstance().promptForUnpublished()) {
          try {
            // Get lock.
            if (MedSavantClient.SettingsManager.getDBLock(
                LoginController.getInstance().getSessionID())) {
              try {
                ProjectWizard wiz =
                    new ProjectWizard(
                        projID,
                        projName,
                        MedSavantClient.PatientManager.getCustomPatientFields(
                            LoginController.getInstance().getSessionID(), projID),
                        MedSavantClient.ProjectManager.getProjectDetails(
                            LoginController.getInstance().getSessionID(), projID));
                wiz.setVisible(true);

              } finally {
                try {
                  MedSavantClient.SettingsManager.releaseDBLock(
                      LoginController.getInstance().getSessionID());
                } catch (Exception ex1) {
                  LOG.error("Error releasing database lock.", ex1);
                }
              }
            } else {
              DialogUtils.displayMessage(
                  "Cannot Modify Project",
                  "The database is currently locked.\nTo unlock, see the Projects page in the Administration section.");
            }
          } catch (Exception ex) {
            ClientMiscUtils.reportError("Error getting database lock: %s", ex);
          }
        }
      } catch (Exception ex) {
        ClientMiscUtils.reportError("Error checking for changes: %s", ex);
      }
    }
  /**
   * Tests the authentication of different calls. Currently tests adding a project, updating a
   * project and getting collections without correct permissions.
   *
   * @throws InvalidXmlException
   * @throws BizInternalException
   * @throws BizPolicyException
   * @throws IOException
   */
  @Test
  public void testAuthentication()
      throws InvalidXmlException, BizInternalException, BizPolicyException, IOException {
    Project newProject = new Project(projectOne);
    newProject.setName("Update");
    newProject.setDescription("foo-update");
    newProject.setEndDate(new DateTime(2014, 2, 10, 0, 0));

    String mimeType = "application/xml";

    // Test updating a project without proper permissions
    MockHttpServletRequest mockReq = newMockRequest("PUT", projectOne.getId(), "test.org", 80);
    MockHttpServletResponse resp = new MockHttpServletResponse();

    ByteArrayOutputStream sink = new ByteArrayOutputStream();
    businessObjectBuilder.buildProject(newProject, sink);

    controller.setAuthenticatedUser(pendingUser);
    controller.handleUpdateProjectRequest(
        projectOne.getId(), mimeType, sink.toByteArray(), mockReq, resp);
    assertNotNull(resp);
    assertEquals(403, resp.getStatus());

    // Test adding a project without proper permissions
    mimeType = "application/xml";
    mockReq = newMockRequest("POST", "/project", "test.org", 80);
    resp = new MockHttpServletResponse();

    sink = new ByteArrayOutputStream();
    newProject.setId("http://test.org/project/2");
    businessObjectBuilder.buildProject(newProject, sink);

    controller.setAuthenticatedUser(pendingUser);
    controller.handleProjectPostRequest(mimeType, sink.toByteArray(), mockReq, resp);
    assertNotNull(resp);
    assertEquals(403, resp.getStatus());

    // Test getting the collections for a project without proper permissions
    mimeType = "application/xml";
    mockReq = newMockRequest("GET", projectOne.getId() + "/collections", "test.org", 80);
    resp = new MockHttpServletResponse();

    when(requestUtil.buildRequestUrl(any(HttpServletRequest.class)))
        .thenReturn(projectOne.getId() + "/collections");

    controller.setAuthenticatedUser(pendingUser);
    controller.handleProjectCollectionsGetRequest(
        projectOne.getId(), mimeType, null, mockReq, resp);
    assertNotNull(resp);
    assertEquals(403, resp.getStatus());
  }
/** @author mfiume */
public class ProjectManagementPage extends SubSectionView {
  private static final Log LOG = LogFactory.getLog(ProjectManagementPage.class);

  private ProjectController controller = ProjectController.getInstance();

  private SplitScreenView view;

  public ProjectManagementPage(SectionView parent) {
    super(parent, "Projects");
    controller.addListener(
        new Listener<ProjectEvent>() {
          @Override
          public void handleEvent(ProjectEvent event) {
            if (view != null) {
              view.refresh();
            }
          }
        });
  }

  @Override
  public JPanel getView() {
    if (view == null) {
      view =
          new SplitScreenView(
              new SimpleDetailedListModel<String>("Projects") {
                @Override
                public String[] getData() throws Exception {
                  return ProjectController.getInstance().getProjectNames();
                }
              },
              new ProjectsDetailedView(),
              new ProjectDetailedListEditor());
    }
    return view;
  }

  @Override
  public Component[] getSubSectionMenuComponents() {
    Component[] result = new Component[0];
    // result[0] = getAddPatientsButton();

    return result;
  }

  private class ProjectDetailedListEditor extends DetailedListEditor {

    @Override
    public boolean doesImplementAdding() {
      return true;
    }

    @Override
    public boolean doesImplementDeleting() {
      return true;
    }

    @Override
    public boolean doesImplementEditing() {
      return true;
    }

    @Override
    public void addItems() {
      try {
        new ProjectWizard().setVisible(true);
      } catch (Exception ex) {
        ClientMiscUtils.reportError("Unable to launch project wizard: %s", ex);
      }
    }

    @Override
    public void editItem(Object[] items) {
      try {
        String projName = (String) items[0];
        int projID =
            MedSavantClient.ProjectManager.getProjectID(
                LoginController.getInstance().getSessionID(), projName);

        // Check for existing unpublished changes to this project.
        if (ProjectController.getInstance().promptForUnpublished()) {
          try {
            // Get lock.
            if (MedSavantClient.SettingsManager.getDBLock(
                LoginController.getInstance().getSessionID())) {
              try {
                ProjectWizard wiz =
                    new ProjectWizard(
                        projID,
                        projName,
                        MedSavantClient.PatientManager.getCustomPatientFields(
                            LoginController.getInstance().getSessionID(), projID),
                        MedSavantClient.ProjectManager.getProjectDetails(
                            LoginController.getInstance().getSessionID(), projID));
                wiz.setVisible(true);

              } finally {
                try {
                  MedSavantClient.SettingsManager.releaseDBLock(
                      LoginController.getInstance().getSessionID());
                } catch (Exception ex1) {
                  LOG.error("Error releasing database lock.", ex1);
                }
              }
            } else {
              DialogUtils.displayMessage(
                  "Cannot Modify Project",
                  "The database is currently locked.\nTo unlock, see the Projects page in the Administration section.");
            }
          } catch (Exception ex) {
            ClientMiscUtils.reportError("Error getting database lock: %s", ex);
          }
        }
      } catch (Exception ex) {
        ClientMiscUtils.reportError("Error checking for changes: %s", ex);
      }
    }

    @Override
    public void deleteItems(List<Object[]> items) {
      int nameIndex = 0;
      int keyIndex = 0;

      int result;

      if (items.size() == 1) {
        String name = (String) items.get(0)[nameIndex];
        result =
            DialogUtils.askYesNo(
                "Confirm",
                "<html>Are you sure you want to remove <i>%s</i>?<br>This cannot be undone.</html>",
                name);
      } else {
        result =
            DialogUtils.askYesNo(
                "Confirm",
                "<html>Are you sure you want to remove these %d projects?<br>This cannot be undone.</html>",
                items.size());
      }

      if (result == DialogUtils.YES) {
        for (Object[] v : items) {
          String projectName = (String) v[keyIndex];
          controller.removeProject(projectName);
        }

        try {
          if (controller.getProjectNames().length == 0) {
            LoginController.getInstance().logout();
          }
          DialogUtils.displayMessage("Successfully removed " + items.size() + " project(s)");
        } catch (Exception ex) {
          ClientMiscUtils.reportError("Unable to get updated project list: %s.", ex);
        }
      }
    }
  }

  private class ProjectsDetailedView extends DetailedView {

    private final JPanel content;
    private String projectName;
    private DetailsWorker detailsWorker;

    private JPanel details;
    private CollapsiblePane infoPanel;

    public ProjectsDetailedView() {
      super(pageName);

      JPanel viewContainer = (JPanel) ViewUtil.clear(this.getContentPanel());
      viewContainer.setLayout(new BorderLayout());

      JPanel infoContainer = ViewUtil.getClearPanel();
      ViewUtil.applyVerticalBoxLayout(infoContainer);

      viewContainer.add(ViewUtil.getClearBorderlessScrollPane(infoContainer), BorderLayout.CENTER);

      CollapsiblePanes panes = new CollapsiblePanes();
      panes.setOpaque(false);
      infoContainer.add(panes);

      infoPanel = new CollapsiblePane();
      infoPanel.setStyle(CollapsiblePane.TREE_STYLE);
      infoPanel.setCollapsible(false);
      panes.add(infoPanel);
      panes.addExpansion();

      content = new JPanel();
      content.setLayout(new BorderLayout());
      infoPanel.setLayout(new BorderLayout());
      infoPanel.add(content, BorderLayout.CENTER);

      details = ViewUtil.getClearPanel();

      content.add(details);
    }

    @Override
    public void setSelectedItem(Object[] item) {
      projectName = (String) item[0];
      refreshSelectedProject();
    }

    private void refreshSelectedProject() {
      infoPanel.setTitle(projectName);

      details.removeAll();
      details.updateUI();

      if (detailsWorker != null) {
        detailsWorker.cancel(true);
      }
      detailsWorker = new DetailsWorker(projectName);
      detailsWorker.execute();
    }

    @Override
    public JPopupMenu createPopup() {
      return null; // nothing yet
    }

    private class DetailsWorker extends MedSavantWorker<ProjectDetails[]> {

      private String projectName;
      Dimension buttonDim = new Dimension(100, 23);

      public DetailsWorker(String projectName) {
        super(pageName);
        this.projectName = projectName;
      }

      @Override
      protected ProjectDetails[] doInBackground() throws Exception {
        int projectId = ProjectController.getInstance().getProjectID(projectName);
        return MedSavantClient.ProjectManager.getProjectDetails(
            LoginController.getInstance().getSessionID(), projectId);
      }

      @Override
      protected void showProgress(double fraction) {
        //
      }

      @Override
      protected void showSuccess(ProjectDetails[] result) {
        setDetailsList(result);
      }
    }

    private synchronized void setDetailsList(ProjectDetails[] projectDetails) {

      details.removeAll();

      ViewUtil.setBoxYLayout(details);

      String[][] values = new String[projectDetails.length][2];
      for (int i = 0; i < projectDetails.length; i++) {
        values[i][0] = projectDetails[i].getReferenceName();
        values[i][1] = projectDetails[i].getNumAnnotations() + " annotation(s) applied";
      }

      details.add(ViewUtil.getKeyValuePairList(values));
      try {
        if (MedSavantClient.SettingsManager.getSetting(
                LoginController.getInstance().getSessionID(), "db lock")
            .equals("true")) {
          JPanel p = new JPanel();
          ViewUtil.applyHorizontalBoxLayout(p);
          p.add(
              ViewUtil.alignLeft(
                  new JLabel(
                      "The database is locked. Administrators cannot make further changes.")));

          JButton b = new JButton("Unlock");
          b.addActionListener(
              new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent ae) {
                  try {
                    int result =
                        DialogUtils.askYesNo(
                            "Warning",
                            "Unlocking the database while another administrator is making changes can\n"
                                + "cause permanent damage. Only unlock if you are sure no one is in the process of\n"
                                + "making changes. Are you sure you want to proceed?");

                    if (result == DialogUtils.YES) {
                      MedSavantClient.SettingsManager.releaseDBLock(
                          LoginController.getInstance().getSessionID());
                      refreshSelectedProject();
                    }
                  } catch (Exception ex) {
                  }
                }
              });
          p.add(b);
          details.add(Box.createVerticalStrut(10));
          details.add(p);
        } else {
          JPanel p = new JPanel();
          ViewUtil.applyHorizontalBoxLayout(p);
          p.add(
              ViewUtil.alignLeft(
                  new JLabel("The database is unlocked. Administrators can make changes.")));

          JButton b = new JButton("Lock");
          b.addActionListener(
              new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent ae) {
                  try {
                    MedSavantClient.SettingsManager.getDBLock(
                        LoginController.getInstance().getSessionID());
                    refreshSelectedProject();
                  } catch (Exception ex) {
                  }
                }
              });
          p.add(b);
          details.add(Box.createVerticalStrut(10));
          details.add(p);
        }
      } catch (Exception ex) {
      }

      details.updateUI();
    }

    @Override
    public void setMultipleSelections(List<Object[]> items) {
      if (items.isEmpty()) {
        infoPanel.setTitle("");
      } else {
        infoPanel.setTitle("Multiple projects (" + items.size() + ")");
      }
      details.removeAll();
      details.updateUI();
    }
  }
}
 @Override
 protected ProjectDetails[] doInBackground() throws Exception {
   int projectId = ProjectController.getInstance().getProjectID(projectName);
   return MedSavantClient.ProjectManager.getProjectDetails(
       LoginController.getInstance().getSessionID(), projectId);
 }
  /**
   * Test getting all the projects for a user
   *
   * @throws InvalidXmlException
   * @throws BizInternalException
   * @throws BizPolicyException
   * @throws IOException
   * @throws ServletException
   */
  @Test
  public void testGetAllProjects()
      throws InvalidXmlException, BizPolicyException, IOException, ServletException {

    // Test getting the list of project without logging in
    final String mimeType = "application/xml";
    final MockHttpServletRequest mockReq = newMockRequest("GET", "/project", "test.org", 80);
    MockHttpServletResponse resp = new MockHttpServletResponse();

    controller.handleEmptyGetRequest(mimeType, null, mockReq, resp);

    assertNotNull(resp);
    assertEquals(401, resp.getStatus());

    // Test getting a single project
    ProjectBizService bizService = mock(ProjectBizService.class);
    HashSet<Project> projects = new HashSet<Project>();
    projects.add(projectOne);

    when(bizService.findByAdmin(admin)).thenReturn(projects);
    controller.setBizService(bizService);

    controller.setAuthenticatedUser(admin);
    resp = new MockHttpServletResponse();
    controller.handleEmptyGetRequest(mimeType, null, mockReq, resp);
    assertNotNull(resp);
    assertEquals(200, resp.getStatus());

    Bop bop =
        businessObjectBuilder.buildBusinessObjectPackage(
            new ByteArrayInputStream(resp.getContentAsByteArray()));
    assertNotNull(bop);
    assertEquals(1, bop.getProjects().size());

    // Test a query that returns no projects

    projects.clear();

    when(bizService.findByAdmin(user)).thenReturn(projects);
    controller.setAuthenticatedUser(user);
    resp = new MockHttpServletResponse();
    controller.handleEmptyGetRequest(mimeType, null, mockReq, resp);
    assertNotNull(resp);
    assertEquals(200, resp.getStatus());

    bop =
        businessObjectBuilder.buildBusinessObjectPackage(
            new ByteArrayInputStream(resp.getContentAsByteArray()));
    assertNotNull(bop);
    assertEquals(0, bop.getProjects().size());

    // Test admin sees all projects in the system
    Project newProject = new Project();
    newProject.setId(testProjectIdTwo);
    newProject.setName("Second_Test_Project");
    newProject.setDescription("foo");
    List<String> numbers = new ArrayList<String>();
    numbers.add("54321");
    numbers.add("9876");
    newProject.setNumbers(numbers);
    newProject.setFundingEntity("moo");
    newProject.setStartDate(new DateTime(2012, 5, 4, 0, 0));
    newProject.setEndDate(new DateTime(2013, 12, 23, 0, 0));
    newProject.addPi(user.getId());
    projectService.create(newProject);

    controller.setBizService(projectBizService);
    controller.setAuthenticatedUser(admin);
    resp = new MockHttpServletResponse();
    controller.handleEmptyGetRequest(mimeType, null, mockReq, resp);
    assertNotNull(resp);
    assertEquals(200, resp.getStatus());

    bop =
        businessObjectBuilder.buildBusinessObjectPackage(
            new ByteArrayInputStream(resp.getContentAsByteArray()));
    assertNotNull(bop);
    assertEquals(projectService.getAll().size(), bop.getProjects().size());
  }
  /**
   * Tests that admin can be added and removed from a project
   *
   * @throws IOException
   * @throws BizPolicyException
   * @throws ProjectServiceException
   * @throws InvalidXmlException
   * @throws BizInternalException
   */
  @Test
  public void testUpdateProjectAdmin()
      throws InvalidXmlException, ProjectServiceException, BizPolicyException, IOException,
          BizInternalException {

    // Test adding an admin to the project.
    Project newProject = new Project(projectOne);
    newProject.addPi(user.getId());

    final String mimeType = "application/xml";
    final MockHttpServletRequest mockReq =
        newMockRequest("PUT", projectOne.getId(), "test.org", 80);

    MockHttpServletResponse resp = new MockHttpServletResponse();

    ByteArrayOutputStream sink = new ByteArrayOutputStream();
    businessObjectBuilder.buildProject(newProject, sink);

    controller.setAuthenticatedUser(admin);
    controller.handleUpdateProjectRequest(
        newProject.getId(), mimeType, sink.toByteArray(), mockReq, resp);

    assertNotNull(resp);
    assertEquals(resp.getErrorMessage(), 200, resp.getStatus());

    Bop bop =
        businessObjectBuilder.buildBusinessObjectPackage(
            new ByteArrayInputStream(resp.getContentAsByteArray()));

    assertNotNull(bop);

    Set<Project> projects = bop.getProjects();
    assertNotNull(projects);
    assertEquals(1, projects.size());

    Project returnedProject = projects.iterator().next();
    assertNotNull(returnedProject);

    assertEquals(newProject.getPis().size(), returnedProject.getPis().size());

    // Test removing an admin from the project.
    newProject.removePi(user.getId());

    resp = new MockHttpServletResponse();

    sink = new ByteArrayOutputStream();
    businessObjectBuilder.buildProject(newProject, sink);

    controller.setAuthenticatedUser(admin);
    controller.handleUpdateProjectRequest(
        newProject.getId(), mimeType, sink.toByteArray(), mockReq, resp);

    assertNotNull(resp);
    bop =
        businessObjectBuilder.buildBusinessObjectPackage(
            new ByteArrayInputStream(resp.getContentAsByteArray()));

    assertNotNull(bop);

    projects = bop.getProjects();
    assertNotNull(projects);
    assertEquals(1, projects.size());

    returnedProject = projects.iterator().next();
    assertNotNull(returnedProject);

    assertEquals(newProject.getPis().size(), returnedProject.getPis().size());
  }