Commit 1e423e01 authored by Evan W. Patton's avatar Evan W. Patton Committed by Jeffrey I. Schiller

Fix project download bug reported by @barreeeiroo

Change-Id: Ibe01541a106b37bffbde21f05ea7f1b2c134070a
parent e4fcdfdd
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2015 MIT, All rights reserved
// Copyright 2015-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -33,7 +33,7 @@ import com.google.appinventor.server.util.PasswordHash;
public class AdminInfoServiceImpl extends OdeRemoteServiceServlet implements AdminInfoService {
// Storage of user settings
private final transient StorageIo storageIo = StorageIoInstanceHolder.INSTANCE;
private final transient StorageIo storageIo = StorageIoInstanceHolder.getInstance();
/**
* Returns a list of AdminUsers, up to 20, based on the starting
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -33,7 +33,7 @@ public class AndroidServlet extends OdeServlet {
// Content type for response header (to avoid security vulnerabilities)
private static final String CONTENT_TYPE = "text/html; charset=utf-8";
private final StorageIo storageIo = StorageIoInstanceHolder.INSTANCE;
private final StorageIo storageIo = StorageIoInstanceHolder.getInstance();
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2015 MIT, All rights reserved
// Copyright 2015-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -39,7 +39,7 @@ public class BlobUpgradeServlet extends OdeServlet {
// Logging support
private static final Logger LOG = Logger.getLogger(BlobUpgradeServlet.class.getName());
private static final CapabilitiesService caps = CapabilitiesServiceFactory.getCapabilitiesService();
private final StorageIo storageIo = StorageIoInstanceHolder.INSTANCE;
private final StorageIo storageIo = StorageIoInstanceHolder.getInstance();
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp)
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2013 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -48,7 +48,7 @@ public class BuildOutputServlet extends OdeServlet {
private final FileExporter fileExporter = new FileExporterImpl();
private final StorageIo storageIo = StorageIoInstanceHolder.INSTANCE;
private final StorageIo storageIo = StorageIoInstanceHolder.getInstance();
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2015-2017 MIT, All rights reserved
// Copyright 2015-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -49,7 +49,7 @@ public class ComponentServiceImpl extends OdeRemoteServiceServlet
private static final Logger LOG =
Logger.getLogger(ComponentServiceImpl.class.getName());
private final transient StorageIo storageIo = StorageIoInstanceHolder.INSTANCE;
private final transient StorageIo storageIo = StorageIoInstanceHolder.getInstance();
private final FileImporter fileImporter = new FileImporterImpl();
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -126,6 +126,7 @@ public class DownloadServlet extends OdeServlet {
// project in the export
boolean includeYail = userInfoProvider.getIsAdmin();
boolean includeScreenShots = includeYail;
StorageIoInstanceHolder.getInstance().assertUserHasProject(userId, projectId);
ProjectSourceZip zipFile = fileExporter.exportProjectSourceZip(userId,
projectId, includeProjectHistory, false, zipName, includeYail,
includeScreenShots, false, false);
......@@ -141,7 +142,7 @@ public class DownloadServlet extends OdeServlet {
String userIdOrEmail = uriComponents[USER_PROJECT_USERID_INDEX];
String projectUserId;
StorageIo storageIo = StorageIoInstanceHolder.INSTANCE;
StorageIo storageIo = StorageIoInstanceHolder.getInstance();
if (userIdOrEmail.contains("@")) {
// email address
try {
......@@ -215,6 +216,17 @@ public class DownloadServlet extends OdeServlet {
}
} catch (IllegalArgumentException e) {
throw CrashReport.createAndLogError(LOG, req, "user=" + userId, e);
} catch (SecurityException e) {
// Not having appropriate permission is akin to not being able to find the project anyway,
// so we use 404 here to not leak that the project may exist.
final String message = "404 Not Found";
resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
resp.setContentType("text/plain");
resp.setContentLength(message.length());
ServletOutputStream out = resp.getOutputStream();
out.write(message.getBytes());
out.close();
return;
}
String fileName = downloadableFile.getFileName();
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2013 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -35,7 +35,7 @@ public class FeedbackServlet extends OdeServlet {
private static final Logger LOG = Logger.getLogger(ReceiveBuildServlet.class.getName());
private final OdeAuthFilter odeFilter = new OdeAuthFilter();
private final transient StorageIo storageIo = StorageIoInstanceHolder.INSTANCE;
private final transient StorageIo storageIo = StorageIoInstanceHolder.getInstance();
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -30,7 +30,7 @@ import javax.annotation.Nullable;
*/
public final class FileExporterImpl implements FileExporter {
private final StorageIo storageIo = StorageIoInstanceHolder.INSTANCE;
private final StorageIo storageIo = StorageIoInstanceHolder.getInstance();
@Override
public RawFile exportProjectOutputFile(String userId, long projectId, @Nullable String target)
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2017 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -51,7 +51,7 @@ public final class FileImporterImpl implements FileImporter {
private static final Logger LOG = Logger.getLogger(FileImporterImpl.class.getName());
private final StorageIo storageIo = StorageIoInstanceHolder.INSTANCE;
private final StorageIo storageIo = StorageIoInstanceHolder.getInstance();
@Override
public UserProject importProject(String userId, String projectName,
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -35,7 +35,7 @@ public class GetMotdServiceImpl extends OdeRemoteServiceServlet implements GetMo
private static final Flag<Integer> motdCheckIntervalSecs =
Flag.createFlag("motd.check.interval.secs", 300);
private final StorageIo storageIo = StorageIoInstanceHolder.INSTANCE;
private final StorageIo storageIo = StorageIoInstanceHolder.getInstance();
private final MemcacheService memcache = MemcacheServiceFactory.getMemcacheService();
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2014 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the MIT License https://raw.github.com/mit-cml/app-inventor/master/mitlicense.txt
package com.google.appinventor.server;
......@@ -65,7 +65,7 @@ import org.owasp.html.PolicyFactory;
@SuppressWarnings("unchecked")
public class LoginServlet extends HttpServlet {
private final StorageIo storageIo = StorageIoInstanceHolder.INSTANCE;
private final StorageIo storageIo = StorageIoInstanceHolder.getInstance();
private static final Logger LOG = Logger.getLogger(LoginServlet.class.getName());
private static final Flag<String> mailServer = Flag.createFlag("localauth.mailserver", "");
private static final Flag<String> password = Flag.createFlag("localauth.mailserver.password", "");
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -56,7 +56,7 @@ public class OdeAuthFilter implements Filter {
private static Crypter crypter = null; // accessed through getCrypter only
private static final Object crypterSync = new Object();
private final StorageIo storageIo = StorageIoInstanceHolder.INSTANCE;
private final StorageIo storageIo = StorageIoInstanceHolder.getInstance();
// Whether this server should use a whitelist to determine who can
// access it. Value is specified in the <system-properties> section
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2017 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -59,7 +59,7 @@ public class ProjectServiceImpl extends OdeRemoteServiceServlet implements Proje
private static final long serialVersionUID = -8316312003804169166L;
private final transient StorageIo storageIo = StorageIoInstanceHolder.INSTANCE;
private final transient StorageIo storageIo = StorageIoInstanceHolder.getInstance();
// RPC implementation for YoungAndroid projects
private final transient YoungAndroidProjectService youngAndroidProject =
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -37,7 +37,7 @@ public class ReceiveBuildServlet extends OdeServlet {
private static final Logger LOG = Logger.getLogger(ReceiveBuildServlet.class.getName());
private final OdeAuthFilter odeFilter = new OdeAuthFilter();
private final transient StorageIo storageIo = StorageIoInstanceHolder.INSTANCE;
private final transient StorageIo storageIo = StorageIoInstanceHolder.getInstance();
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -101,7 +101,7 @@ public class RendezvousServlet extends HttpServlet {
private final String rendezvousuuid = "c96d8ac6-e571-48bb-9e1f-58df18574e43"; // UUID Generated by JIS
private final StorageIo storageIo = StorageIoInstanceHolder.INSTANCE;
private final StorageIo storageIo = StorageIoInstanceHolder.getInstance();
public void init(ServletConfig config) throws ServletException {
super.init(config);
......
......@@ -28,7 +28,7 @@ public class TosServlet extends OdeServlet {
// Logging support
private static final Logger LOG = Logger.getLogger(TosServlet.class.getName());
private final StorageIo storageIo = StorageIoInstanceHolder.INSTANCE;
private final StorageIo storageIo = StorageIoInstanceHolder.getInstance();
private static final long serialVersionUID = 8099788377554316289L;
// An URL to redirect requests to the first time they access App Inventor.
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -24,7 +24,7 @@ import com.google.appinventor.shared.storage.StorageUtil;
public class UserInfoServiceImpl extends OdeRemoteServiceServlet implements UserInfoService {
// Storage of user settings
private final transient StorageIo storageIo = StorageIoInstanceHolder.INSTANCE;
private final transient StorageIo storageIo = StorageIoInstanceHolder.getInstance();
private static final long serialVersionUID = -7316312435338169166L;
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -91,7 +91,7 @@ public class ObjectifyGalleryStorageIo implements GalleryStorageIo {
// we'll need to talk to the StorageIo to get developer names, so...
private final transient StorageIo storageIo =
StorageIoInstanceHolder.INSTANCE;
StorageIoInstanceHolder.getInstance();
/**
* creates a new gallery app
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -2941,4 +2941,25 @@ public class ObjectifyStorageIo implements StorageIo {
return ival.intValue();
}
}
@Override
public void assertUserHasProject(final String userId, final long projectId) {
try {
runJobWithRetries(new JobRetryHelper() {
@SuppressWarnings("RedundantThrows")
@Override
public void run(Objectify datastore) throws ObjectifyException, IOException {
Key<UserData> userKey = userKey(userId);
Key<UserProjectData> userProjectKey = userProjectKey(userKey, projectId);
UserProjectData data = datastore.find(userProjectKey);
if (data == null) { // User doesn't have the corresponding project.
throw new SecurityException("Unauthorized access");
}
// User has data for project, so everything checks out.
}
}, false);
} catch(ObjectifyException e) {
throw CrashReport.createAndLogError(LOG, null, null, e);
}
}
}
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -706,4 +706,15 @@ public interface StorageIo {
public int getBuildStatus(String userId, long projectId);
/**
* Checks that the user identified by {@code userId} has a reference to the project identified
* by {@code projectId}. If a corresponding UserProjectData is not found, this function throws
* a SecurityException to indicate unauthorized access.
*
* @param userId id for the user
* @param projectId id for the project
* @throws SecurityException if the user doesn't have access to the project
*/
void assertUserHasProject(String userId, long projectId);
}
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.server.storage;
import com.google.common.annotations.VisibleForTesting;
/**
* Holds the singleton StorageIo subclass object. We introduce this class
* so that we can switch out the underlying StorageIo subclass without changing
......@@ -15,8 +17,19 @@ package com.google.appinventor.server.storage;
*
*/
public class StorageIoInstanceHolder {
public static final StorageIo INSTANCE = new ObjectifyStorageIo();
private static StorageIo INSTANCE;
private StorageIoInstanceHolder() {} // not to be instantiated
public static StorageIo getInstance() {
if (INSTANCE == null) {
INSTANCE = new ObjectifyStorageIo();
}
return INSTANCE;
}
@VisibleForTesting
public static void setInstance(StorageIo instance) {
INSTANCE = instance;
}
}
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2017 MIT, All rights reserved
// Copyright 2017-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -316,7 +316,8 @@ public class ComponentServiceTest {
}
private void assertAssetsWithPrefixRemoved(String prefix) {
List<String> files = StorageIoInstanceHolder.INSTANCE.getProjectSourceFiles("1", projectId);
List<String> files = StorageIoInstanceHolder.getInstance()
.getProjectSourceFiles("1", projectId);
for (String name : files) {
if (name.startsWith(prefix)) {
fail("Expected for file " + name + " to be deleted.");
......@@ -325,7 +326,8 @@ public class ComponentServiceTest {
}
private void assertAssetsOnServer(String path) {
List<String> files = StorageIoInstanceHolder.INSTANCE.getProjectSourceFiles("1", projectId);
List<String> files = StorageIoInstanceHolder.getInstance()
.getProjectSourceFiles("1", projectId);
for (String name : files) {
if (name.equals(path)) {
return;
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.server;
import com.google.appinventor.server.storage.StorageIo;
import com.google.appinventor.server.storage.StorageIoInstanceHolder;
import com.google.appinventor.shared.rpc.project.ProjectSourceZip;
import com.google.appinventor.shared.rpc.project.RawFile;
import com.riq.MockHttpServletRequest;
......@@ -17,6 +19,7 @@ import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
......@@ -50,6 +53,7 @@ public class DownloadServletTest {
private FileExporterImpl exporterMock;
private LocalUser localUserMock;
private StorageIo storageIoMock;
@Before
public void setUp() throws Exception {
......@@ -60,6 +64,9 @@ public class DownloadServletTest {
exporterMock = PowerMock.createNiceMock(FileExporterImpl.class);
PowerMock.expectNew(FileExporterImpl.class).andReturn(exporterMock).anyTimes();
storageIoMock = PowerMock.createNiceMock(StorageIo.class);
StorageIoInstanceHolder.setInstance(storageIoMock);
dummyZip = new ProjectSourceZip(DUMMY_ZIP_FILENAME, new byte[] {}, 2);
dummyZipWithTitle = new ProjectSourceZip(DUMMY_ZIP_FILENAME_WITH_TITLE, new byte[] {}, 2);
dummyApk = new RawFile(DUMMY_APK_FILENAME, new byte[] {});
......@@ -74,6 +81,8 @@ public class DownloadServletTest {
@Test
public void testDownloadProjectSourceZipWithoutTitle() throws Exception {
storageIoMock.assertUserHasProject(USER_ID, PROJECT_ID);
PowerMock.expectLastCall().once();
MockHttpServletRequest request = new MockHttpServletRequest(DOWNLOAD_URL +
"project-source/1234");
expect(exporterMock.exportProjectSourceZip(USER_ID, PROJECT_ID, true, false, null, false, false, false, false))
......@@ -89,6 +98,8 @@ public class DownloadServletTest {
@Test
public void testDownloadProjectSourceZipWithTitle() throws IOException {
storageIoMock.assertUserHasProject(USER_ID, PROJECT_ID);
PowerMock.expectLastCall().once();
MockHttpServletRequest request = new MockHttpServletRequest(DOWNLOAD_URL +
"project-source/1234/My Project Title 123");
expect(exporterMock.exportProjectSourceZip(USER_ID, PROJECT_ID, true, false,
......@@ -105,20 +116,15 @@ public class DownloadServletTest {
@Test
public void testDownloadProjectSourceZipWithNonExistingProject() throws IOException {
IllegalArgumentException expectedException = new IllegalArgumentException();
storageIoMock.assertUserHasProject(USER_ID, 12345L);
PowerMock.expectLastCall().andThrow(new SecurityException());
PowerMock.replayAll();
MockHttpServletRequest request = new MockHttpServletRequest(DOWNLOAD_URL +
"project-source/12345");
expect(exporterMock.exportProjectSourceZip(USER_ID, 12345L, true, false, null, false, false, false, false))
.andThrow(expectedException);
PowerMock.replayAll();
DownloadServlet download = new DownloadServlet();
try {
download.doGet(request, new MockHttpServletResponse());
fail();
} catch (IllegalArgumentException ex) {
assertEquals(expectedException, ex);
}
PowerMock.verifyAll();
MockHttpServletResponse response = new MockHttpServletResponse();
download.doGet(request, response);
assertEquals(HttpServletResponse.SC_NOT_FOUND, response.getStatus());
}
@Test
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -58,7 +58,7 @@ public class FileExporterImplTest extends LocalDatastoreTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
storageIo = StorageIoInstanceHolder.INSTANCE;
storageIo = StorageIoInstanceHolder.getInstance();
exporter = new FileExporterImpl();
Project project = new Project(PROJECT_NAME);
project.setProjectType(FAKE_PROJECT_TYPE);
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -43,7 +43,7 @@ public class FileImporterImplTest extends LocalDatastoreTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
storageIo = StorageIoInstanceHolder.INSTANCE;
storageIo = StorageIoInstanceHolder.getInstance();
// Create user with given parameters
storageIo.getUser(USER_ID, USER_EMAIL_ADDRESS);
fileImporter = new FileImporterImpl();
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2017 MIT, All rights reserved
// Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -103,7 +103,7 @@ public class ProjectServiceTest {
@Before
public void setUp() throws Exception {
helper.setUp();
storageIo = StorageIoInstanceHolder.INSTANCE;
storageIo = StorageIoInstanceHolder.getInstance();
PowerMock.mockStatic(LocalUser.class);
localUserMock = PowerMock.createMock(LocalUser.class);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment