Java tutorial
/*! * Copyright 2010 - 2015 Pentaho Corporation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.pentaho.di.repository.pur; import static org.junit.Assert.*; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.io.File; import java.io.IOException; import java.io.Serializable; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.Callable; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.Workspace; import javax.jcr.security.AccessControlException; import javax.xml.parsers.SAXParserFactory; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.reflect.FieldUtils; import org.apache.commons.vfs2.FileObject; import org.apache.jackrabbit.api.JackrabbitWorkspace; import org.apache.jackrabbit.api.security.authorization.PrivilegeManager; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.pentaho.di.cluster.ClusterSchema; import org.pentaho.di.cluster.SlaveServer; import org.pentaho.di.core.KettleEnvironment; import org.pentaho.di.core.ProgressMonitorListener; import org.pentaho.di.core.database.DatabaseMeta; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.plugins.JobEntryPluginType; import org.pentaho.di.core.plugins.StepPluginType; import org.pentaho.di.core.vfs.KettleVFS; import org.pentaho.di.job.JobMeta; import org.pentaho.di.partition.PartitionSchema; import org.pentaho.di.repository.ObjectId; import org.pentaho.di.repository.ObjectRevision; import org.pentaho.di.repository.RepositoryDirectoryInterface; import org.pentaho.di.repository.RepositoryElementInterface; import org.pentaho.di.repository.RepositoryObject; import org.pentaho.di.repository.RepositoryObjectType; import org.pentaho.di.repository.RepositoryTestBase; import org.pentaho.di.repository.StringObjectId; import org.pentaho.di.repository.UserInfo; import org.pentaho.di.repository.pur.metastore.MetaStoreTestBase; import org.pentaho.di.shared.SharedObjectInterface; import org.pentaho.di.trans.TransMeta; import org.pentaho.di.trans.step.StepMeta; import org.pentaho.di.trans.steps.tableinput.TableInputMeta; import org.pentaho.metastore.api.IMetaStore; import org.pentaho.metastore.api.IMetaStoreAttribute; import org.pentaho.metastore.api.IMetaStoreElement; import org.pentaho.metastore.api.IMetaStoreElementType; import org.pentaho.metastore.api.exceptions.MetaStoreDependenciesExistsException; import org.pentaho.metastore.api.exceptions.MetaStoreException; import org.pentaho.metastore.api.exceptions.MetaStoreNamespaceExistsException; import org.pentaho.metastore.util.PentahoDefaults; import org.pentaho.platform.api.engine.IAuthorizationPolicy; import org.pentaho.platform.api.engine.IPentahoSession; import org.pentaho.platform.api.engine.security.userroledao.IPentahoRole; import org.pentaho.platform.api.engine.security.userroledao.IPentahoUser; import org.pentaho.platform.api.engine.security.userroledao.IUserRoleDao; import org.pentaho.platform.api.mt.ITenant; import org.pentaho.platform.api.mt.ITenantManager; import org.pentaho.platform.api.mt.ITenantedPrincipleNameResolver; import org.pentaho.platform.api.repository2.unified.IBackingRepositoryLifecycleManager; import org.pentaho.platform.api.repository2.unified.IRepositoryVersionManager; import org.pentaho.platform.api.repository2.unified.IUnifiedRepository; import org.pentaho.platform.api.repository2.unified.RepositoryFile; import org.pentaho.platform.api.repository2.unified.RepositoryFileAcl; import org.pentaho.platform.api.repository2.unified.RepositoryFileAcl.Builder; import org.pentaho.platform.api.repository2.unified.RepositoryFilePermission; import org.pentaho.platform.api.repository2.unified.RepositoryFileSid; import org.pentaho.platform.api.repository2.unified.RepositoryFileSid.Type; import org.pentaho.platform.core.mt.Tenant; import org.pentaho.platform.engine.core.system.PentahoSessionHolder; import org.pentaho.platform.engine.core.system.StandaloneSession; import org.pentaho.platform.repository2.ClientRepositoryPaths; import org.pentaho.platform.repository2.unified.IRepositoryFileDao; import org.pentaho.platform.repository2.unified.ServerRepositoryPaths; import org.pentaho.platform.repository2.unified.jcr.JcrRepositoryFileUtils; import org.pentaho.platform.repository2.unified.jcr.JcrTenantUtils; import org.pentaho.platform.repository2.unified.jcr.PentahoJcrConstants; import org.pentaho.platform.repository2.unified.jcr.RepositoryFileProxyFactory; import org.pentaho.platform.repository2.unified.jcr.SimpleJcrTestUtils; import org.pentaho.platform.repository2.unified.jcr.jackrabbit.security.TestPrincipalProvider; import org.pentaho.platform.repository2.unified.jcr.sejcr.CredentialsStrategy; import org.pentaho.platform.security.policy.rolebased.IRoleAuthorizationPolicyRoleBindingDao; import org.pentaho.platform.security.userroledao.DefaultTenantedPrincipleNameResolver; import org.pentaho.test.platform.engine.core.MicroPlatform; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.extensions.jcr.JcrCallback; import org.springframework.extensions.jcr.JcrTemplate; import org.springframework.extensions.jcr.SessionFactory; import org.springframework.security.Authentication; import org.springframework.security.GrantedAuthority; import org.springframework.security.GrantedAuthorityImpl; import org.springframework.security.context.SecurityContextHolder; import org.springframework.security.providers.UsernamePasswordAuthenticationToken; import org.springframework.security.userdetails.User; import org.springframework.security.userdetails.UserDetails; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.ext.DefaultHandler2; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:/repository.spring.xml", "classpath:/repository-test-override.spring.xml" }) public class PurRepositoryTest extends RepositoryTestBase implements ApplicationContextAware, java.io.Serializable { static final long serialVersionUID = 2064159405078106703L; /* EESOURCE: UPDATE SERIALVERUID */ private IUnifiedRepository repo; private ITenantedPrincipleNameResolver userNameUtils = new DefaultTenantedPrincipleNameResolver(); private ITenantedPrincipleNameResolver roleNameUtils = new DefaultTenantedPrincipleNameResolver( DefaultTenantedPrincipleNameResolver.ALTERNATE_DELIMETER); private ITenantManager tenantManager; private ITenant systemTenant; private IRoleAuthorizationPolicyRoleBindingDao roleBindingDaoTarget; private String repositoryAdminUsername; private JcrTemplate testJcrTemplate; private MicroPlatform mp; IUserRoleDao testUserRoleDao; IUserRoleDao userRoleDao; private String singleTenantAdminRoleName; private String tenantAuthenticatedRoleName; private String sysAdminUserName; private String superAdminRoleName; private TransactionTemplate txnTemplate; private IRepositoryFileDao repositoryFileDao; private final String TENANT_ID_ACME = "acme"; private IBackingRepositoryLifecycleManager repositoryLifecyleManager; private final String TENANT_ID_DUFF = "duff"; private static IAuthorizationPolicy authorizationPolicy; // ~ Methods ========================================================================================================= @BeforeClass public static void setUpClass() throws Exception { System.out.println("Repository: " + PurRepositoryTest.class.getClassLoader().getResource("repository.spring.xml").getPath()); // folder cannot be deleted at teardown shutdown hooks have not yet necessarily completed // parent folder must match jcrRepository.homeDir bean property in repository-test-override.spring.xml FileUtils.deleteDirectory(new File("/tmp/jackrabbit-test-TRUNK")); PentahoSessionHolder.setStrategyName(PentahoSessionHolder.MODE_GLOBAL); } @AfterClass public static void tearDownClass() throws Exception { PentahoSessionHolder.setStrategyName(PentahoSessionHolder.MODE_INHERITABLETHREADLOCAL); } @Before public void setUp() throws Exception { IRepositoryVersionManager mockRepositoryVersionManager = mock(IRepositoryVersionManager.class); when(mockRepositoryVersionManager.isVersioningEnabled(anyString())).thenReturn(true); when(mockRepositoryVersionManager.isVersionCommentEnabled(anyString())).thenReturn(false); JcrRepositoryFileUtils.setRepositoryVersionManager(mockRepositoryVersionManager); loginAsRepositoryAdmin(); SimpleJcrTestUtils.deleteItem(testJcrTemplate, ServerRepositoryPaths.getPentahoRootFolderPath()); mp = new MicroPlatform(); // used by DefaultPentahoJackrabbitAccessControlHelper mp.defineInstance("tenantedUserNameUtils", userNameUtils); mp.defineInstance("tenantedRoleNameUtils", roleNameUtils); mp.defineInstance(IAuthorizationPolicy.class, authorizationPolicy); mp.defineInstance(ITenantManager.class, tenantManager); mp.defineInstance("roleAuthorizationPolicyRoleBindingDaoTarget", roleBindingDaoTarget); mp.defineInstance("repositoryAdminUsername", repositoryAdminUsername); mp.defineInstance("RepositoryFileProxyFactory", new RepositoryFileProxyFactory(testJcrTemplate, repositoryFileDao)); mp.defineInstance("useMultiByteEncoding", new Boolean(false)); // Start the micro-platform mp.start(); loginAsRepositoryAdmin(); setAclManagement(); systemTenant = tenantManager.createTenant(null, ServerRepositoryPaths.getPentahoRootFolderName(), singleTenantAdminRoleName, tenantAuthenticatedRoleName, "Anonymous"); userRoleDao.createUser(systemTenant, sysAdminUserName, "password", "", new String[] { singleTenantAdminRoleName }); logout(); super.setUp(); KettleEnvironment.init(); // programmatically register plugins, annotation based plugins do not get loaded unless // they are in kettle's plugins folder. JobEntryPluginType.getInstance().registerCustom(JobEntryAttributeTesterJobEntry.class, "test", "JobEntryAttributeTester", "JobEntryAttributeTester", "JobEntryAttributeTester", ""); StepPluginType.getInstance().registerCustom(TransStepAttributeTesterTransStep.class, "test", "StepAttributeTester", "StepAttributeTester", "StepAttributeTester", ""); repositoryMeta = new PurRepositoryMeta(); repositoryMeta.setName("JackRabbit"); repositoryMeta.setDescription("JackRabbit test repository"); userInfo = new UserInfo(EXP_LOGIN, "password", EXP_USERNAME, "Apache Tomcat user", true); repository = new PurRepository(); repository.init(repositoryMeta); login(sysAdminUserName, systemTenant, new String[] { singleTenantAdminRoleName, tenantAuthenticatedRoleName }); ITenant tenantAcme = tenantManager.createTenant(systemTenant, EXP_TENANT, singleTenantAdminRoleName, tenantAuthenticatedRoleName, "Anonymous"); userRoleDao.createUser(tenantAcme, EXP_LOGIN, "password", "", new String[] { singleTenantAdminRoleName }); logout(); setUpUser(); PurRepository purRep = (PurRepository) repository; purRep.setPurRepositoryConnector( new PurRepositoryConnector(purRep, (PurRepositoryMeta) repositoryMeta, purRep.getRootRef())); ((PurRepository) repository).setTest(repo); repository.connect(EXP_LOGIN, "password"); login(EXP_LOGIN, tenantAcme, new String[] { singleTenantAdminRoleName, tenantAuthenticatedRoleName }); System.out.println("PUR NAME!!!: " + repo.getClass().getCanonicalName()); RepositoryFile repositoryFile = repo.getFile(ClientRepositoryPaths.getPublicFolderPath()); Serializable repositoryFileId = repositoryFile.getId(); List<RepositoryFile> files = repo.getChildren(repositoryFileId); StringBuilder buf = new StringBuilder(); for (RepositoryFile file : files) { buf.append("\n").append(file); } assertTrue("files not deleted: " + buf, files.isEmpty()); } private void setAclManagement() { testJcrTemplate.execute(new JcrCallback() { @Override public Object doInJcr(Session session) throws IOException, RepositoryException { PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session); Workspace workspace = session.getWorkspace(); PrivilegeManager privilegeManager = ((JackrabbitWorkspace) workspace).getPrivilegeManager(); try { privilegeManager.getPrivilege(pentahoJcrConstants.getPHO_ACLMANAGEMENT_PRIVILEGE()); } catch (AccessControlException ace) { privilegeManager.registerPrivilege(pentahoJcrConstants.getPHO_ACLMANAGEMENT_PRIVILEGE(), false, new String[0]); } session.save(); return null; } }); } protected void setUpUser() { StandaloneSession pentahoSession = new StandaloneSession(userInfo.getLogin()); pentahoSession.setAuthenticated(userInfo.getLogin()); pentahoSession.setAttribute(IPentahoSession.TENANT_ID_KEY, "/pentaho/" + EXP_TENANT); final GrantedAuthority[] authorities = new GrantedAuthority[2]; authorities[0] = new GrantedAuthorityImpl("Authenticated"); authorities[1] = new GrantedAuthorityImpl("acme_Authenticated"); final String password = "ignored"; //$NON-NLS-1$ UserDetails userDetails = new User(userInfo.getLogin(), password, true, true, true, true, authorities); Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, password, authorities); // next line is copy of SecurityHelper.setPrincipal pentahoSession.setAttribute("SECURITY_PRINCIPAL", authentication); PentahoSessionHolder.setSession(pentahoSession); SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_GLOBAL); SecurityContextHolder.getContext().setAuthentication(authentication); repositoryLifecyleManager.newTenant(); repositoryLifecyleManager.newUser(); } protected void loginAsRepositoryAdmin() { StandaloneSession pentahoSession = new StandaloneSession(repositoryAdminUsername); pentahoSession.setAuthenticated(repositoryAdminUsername); final GrantedAuthority[] repositoryAdminAuthorities = new GrantedAuthority[] { new GrantedAuthorityImpl(superAdminRoleName) }; final String password = "ignored"; UserDetails repositoryAdminUserDetails = new User(repositoryAdminUsername, password, true, true, true, true, repositoryAdminAuthorities); Authentication repositoryAdminAuthentication = new UsernamePasswordAuthenticationToken( repositoryAdminUserDetails, password, repositoryAdminAuthorities); PentahoSessionHolder.setSession(pentahoSession); // this line necessary for Spring Security's MethodSecurityInterceptor SecurityContextHolder.getContext().setAuthentication(repositoryAdminAuthentication); } protected void logout() { PentahoSessionHolder.removeSession(); SecurityContextHolder.getContext().setAuthentication(null); } protected void loginAsTenantAdmin() { StandaloneSession pentahoSession = new StandaloneSession("joe"); pentahoSession.setAuthenticated("joe"); pentahoSession.setAttribute(IPentahoSession.TENANT_ID_KEY, "acme"); final String password = "password"; List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(); authList.add(new GrantedAuthorityImpl("Authenticated")); authList.add(new GrantedAuthorityImpl("acme_Authenticated")); authList.add(new GrantedAuthorityImpl("acme_Admin")); GrantedAuthority[] authorities = authList.toArray(new GrantedAuthority[0]); UserDetails userDetails = new User("joe", password, true, true, true, true, authorities); Authentication auth = new UsernamePasswordAuthenticationToken(userDetails, password, authorities); PentahoSessionHolder.setSession(pentahoSession); // this line necessary for Spring Security's MethodSecurityInterceptor SecurityContextHolder.getContext().setAuthentication(auth); repositoryLifecyleManager.newTenant(); repositoryLifecyleManager.newUser(); } /** * Logs in with given username. * * @param username username of user * @param tenantId tenant to which this user belongs * @tenantAdmin true to add the tenant admin authority to the user's roles */ protected void login(final String username, final ITenant tenant, String[] roles) { StandaloneSession pentahoSession = new StandaloneSession(username); pentahoSession.setAuthenticated(tenant.getId(), username); PentahoSessionHolder.setSession(pentahoSession); pentahoSession.setAttribute(IPentahoSession.TENANT_ID_KEY, tenant.getId()); final String password = "password"; List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(); for (String roleName : roles) { authList.add(new GrantedAuthorityImpl(roleName)); } GrantedAuthority[] authorities = authList.toArray(new GrantedAuthority[0]); UserDetails userDetails = new User(username, password, true, true, true, true, authorities); Authentication auth = new UsernamePasswordAuthenticationToken(userDetails, password, authorities); PentahoSessionHolder.setSession(pentahoSession); // this line necessary for Spring Security's MethodSecurityInterceptor SecurityContextHolder.getContext().setAuthentication(auth); createUserHomeFolder(tenant, username); } protected ITenant getTenant(String principalId, boolean isUser) { ITenant tenant = null; ITenantedPrincipleNameResolver nameUtils = isUser ? userNameUtils : roleNameUtils; if (nameUtils != null) { tenant = nameUtils.getTenant(principalId); } if (tenant == null || tenant.getId() == null) { tenant = getCurrentTenant(); } return tenant; } protected ITenant getCurrentTenant() { if (PentahoSessionHolder.getSession() != null) { String tenantId = (String) PentahoSessionHolder.getSession() .getAttribute(IPentahoSession.TENANT_ID_KEY); return tenantId != null ? new Tenant(tenantId, true) : null; } else { return null; } } protected String getPrincipalName(String principalId, boolean isUser) { String principalName = null; ITenantedPrincipleNameResolver nameUtils = isUser ? userNameUtils : roleNameUtils; if (nameUtils != null) { principalName = nameUtils.getPrincipleName(principalId); } return principalName; } protected void createUserHomeFolder(final ITenant theTenant, final String theUsername) { IPentahoSession origPentahoSession = PentahoSessionHolder.getSession(); Authentication origAuthentication = SecurityContextHolder.getContext().getAuthentication(); StandaloneSession pentahoSession = new StandaloneSession(repositoryAdminUsername); pentahoSession.setAuthenticated(null, repositoryAdminUsername); PentahoSessionHolder.setSession(pentahoSession); try { txnTemplate.execute(new TransactionCallbackWithoutResult() { public void doInTransactionWithoutResult(final TransactionStatus status) { Builder aclsForUserHomeFolder = null; Builder aclsForTenantHomeFolder = null; ITenant tenant = null; String username = null; if (theTenant == null) { tenant = getTenant(username, true); username = getPrincipalName(theUsername, true); } else { tenant = theTenant; username = theUsername; } if (tenant == null || tenant.getId() == null) { tenant = getCurrentTenant(); } if (tenant == null || tenant.getId() == null) { tenant = JcrTenantUtils.getDefaultTenant(); } RepositoryFile userHomeFolder = null; String userId = userNameUtils.getPrincipleId(theTenant, username); final RepositoryFileSid userSid = new RepositoryFileSid(userId); RepositoryFile tenantHomeFolder = null; RepositoryFile tenantRootFolder = null; // Get the Tenant Root folder. If the Tenant Root folder does not exist then exit. tenantRootFolder = repositoryFileDao .getFileByAbsolutePath(ServerRepositoryPaths.getTenantRootFolderPath(theTenant)); if (tenantRootFolder != null) { // Try to see if Tenant Home folder exist tenantHomeFolder = repositoryFileDao .getFileByAbsolutePath(ServerRepositoryPaths.getTenantHomeFolderPath(theTenant)); if (tenantHomeFolder == null) { String ownerId = userNameUtils.getPrincipleId(theTenant, username); RepositoryFileSid ownerSid = new RepositoryFileSid(ownerId, Type.USER); String tenantAuthenticatedRoleId = roleNameUtils.getPrincipleId(theTenant, tenantAuthenticatedRoleName); RepositoryFileSid tenantAuthenticatedRoleSid = new RepositoryFileSid( tenantAuthenticatedRoleId, Type.ROLE); aclsForTenantHomeFolder = new RepositoryFileAcl.Builder(userSid) .ace(tenantAuthenticatedRoleSid, EnumSet.of(RepositoryFilePermission.READ)); aclsForUserHomeFolder = new RepositoryFileAcl.Builder(userSid).ace(ownerSid, EnumSet.of(RepositoryFilePermission.ALL)); tenantHomeFolder = repositoryFileDao.createFolder(tenantRootFolder.getId(), new RepositoryFile.Builder(ServerRepositoryPaths.getTenantHomeFolderName()) .folder(true).build(), aclsForTenantHomeFolder.build(), "tenant home folder"); } else { String ownerId = userNameUtils.getPrincipleId(theTenant, username); RepositoryFileSid ownerSid = new RepositoryFileSid(ownerId, Type.USER); aclsForUserHomeFolder = new RepositoryFileAcl.Builder(userSid).ace(ownerSid, EnumSet.of(RepositoryFilePermission.ALL)); } // now check if user's home folder exist userHomeFolder = repositoryFileDao.getFileByAbsolutePath( ServerRepositoryPaths.getUserHomeFolderPath(theTenant, username)); if (userHomeFolder == null) { userHomeFolder = repositoryFileDao.createFolder(tenantHomeFolder.getId(), new RepositoryFile.Builder(username).folder(true).build(), aclsForUserHomeFolder.build(), "user home folder"); //$NON-NLS-1$ } } } }); } finally { // Switch our identity back to the original user. PentahoSessionHolder.setSession(origPentahoSession); SecurityContextHolder.getContext().setAuthentication(origAuthentication); } } private void cleanupUserAndRoles(final ITenant tenant) { loginAsRepositoryAdmin(); for (IPentahoRole role : testUserRoleDao.getRoles(tenant)) { testUserRoleDao.deleteRole(role); } for (IPentahoUser user : testUserRoleDao.getUsers(tenant)) { testUserRoleDao.deleteUser(user); } } @After public void tearDown() throws Exception { // null out fields to get back memory authorizationPolicy = null; login(sysAdminUserName, systemTenant, new String[] { singleTenantAdminRoleName, tenantAuthenticatedRoleName }); ITenant tenant = tenantManager .getTenant("/" + ServerRepositoryPaths.getPentahoRootFolderName() + "/" + TENANT_ID_ACME); if (tenant != null) { cleanupUserAndRoles(tenant); } login(sysAdminUserName, systemTenant, new String[] { singleTenantAdminRoleName, tenantAuthenticatedRoleName }); tenant = tenantManager .getTenant("/" + ServerRepositoryPaths.getPentahoRootFolderName() + "/" + TENANT_ID_DUFF); if (tenant != null) { cleanupUserAndRoles(tenant); } cleanupUserAndRoles(systemTenant); SimpleJcrTestUtils.deleteItem(testJcrTemplate, ServerRepositoryPaths.getPentahoRootFolderPath()); logout(); repositoryAdminUsername = null; singleTenantAdminRoleName = null; tenantAuthenticatedRoleName = null; // roleBindingDao = null; authorizationPolicy = null; testJcrTemplate = null; // null out fields to get back memory tenantManager = null; repo = null; } @Override protected void delete(ObjectId id) { if (id != null) { repo.deleteFile(id.getId(), true, null); } } /** * Tries twice to delete files. By not failing outright on the first pass, we hopefully eliminate files that are * holding references to the files we cannot delete. */ protected void safelyDeleteAll(final ObjectId[] ids) throws Exception { Exception firstException = null; List<String> frozenIds = new ArrayList<String>(); for (ObjectId id : ids) { frozenIds.add(id.getId()); } List<String> remainingIds = new ArrayList<String>(); for (ObjectId id : ids) { remainingIds.add(id.getId()); } try { for (int i = 0; i < frozenIds.size(); i++) { repo.deleteFile(frozenIds.get(i), true, null); remainingIds.remove(frozenIds.get(i)); } } catch (Exception e) { e.printStackTrace(); } if (!remainingIds.isEmpty()) { List<String> frozenIds2 = remainingIds; List<String> remainingIds2 = new ArrayList<String>(); for (String id : frozenIds2) { remainingIds2.add(id); } try { for (int i = 0; i < frozenIds2.size(); i++) { repo.deleteFile(frozenIds2.get(i), true, null); remainingIds2.remove(frozenIds2.get(i)); } } catch (Exception e) { if (firstException == null) { firstException = e; } } if (!remainingIds2.isEmpty()) { throw firstException; } } } @Override public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException { SessionFactory jcrSessionFactory = (SessionFactory) applicationContext.getBean("jcrSessionFactory"); testJcrTemplate = new JcrTemplate(jcrSessionFactory); testJcrTemplate.setAllowCreate(true); testJcrTemplate.setExposeNativeSession(true); repositoryAdminUsername = (String) applicationContext.getBean("repositoryAdminUsername"); superAdminRoleName = (String) applicationContext.getBean("superAdminAuthorityName"); sysAdminUserName = (String) applicationContext.getBean("superAdminUserName"); tenantAuthenticatedRoleName = (String) applicationContext.getBean("singleTenantAuthenticatedAuthorityName"); singleTenantAdminRoleName = (String) applicationContext.getBean("singleTenantAdminAuthorityName"); tenantManager = (ITenantManager) applicationContext.getBean("tenantMgrProxy"); roleBindingDaoTarget = (IRoleAuthorizationPolicyRoleBindingDao) applicationContext .getBean("roleAuthorizationPolicyRoleBindingDaoTarget"); authorizationPolicy = (IAuthorizationPolicy) applicationContext.getBean("authorizationPolicy"); repo = (IUnifiedRepository) applicationContext.getBean("unifiedRepository"); userRoleDao = (IUserRoleDao) applicationContext.getBean("userRoleDao"); repositoryFileDao = (IRepositoryFileDao) applicationContext.getBean("repositoryFileDao"); testUserRoleDao = userRoleDao; repositoryLifecyleManager = (IBackingRepositoryLifecycleManager) applicationContext .getBean("defaultBackingRepositoryLifecycleManager"); txnTemplate = (TransactionTemplate) applicationContext.getBean("jcrTransactionTemplate"); TestPrincipalProvider.userRoleDao = testUserRoleDao; TestPrincipalProvider.adminCredentialsStrategy = (CredentialsStrategy) applicationContext .getBean("jcrAdminCredentialsStrategy"); TestPrincipalProvider.repository = (Repository) applicationContext.getBean("jcrRepository"); } @Override protected RepositoryDirectoryInterface loadStartDirectory() throws Exception { RepositoryDirectoryInterface rootDir = repository.loadRepositoryDirectoryTree(); RepositoryDirectoryInterface startDir = rootDir.findDirectory("public"); assertNotNull(startDir); return startDir; } /** * Allow PentahoSystem to create this class but it in turn delegates to the authorizationPolicy fetched from Spring's * ApplicationContext. */ public static class DelegatingAuthorizationPolicy implements IAuthorizationPolicy { public List<String> getAllowedActions(final String actionNamespace) { return authorizationPolicy.getAllowedActions(actionNamespace); } public boolean isAllowed(final String actionName) { return authorizationPolicy.isAllowed(actionName); } } @Test public void testLoadSharedObjects_databases() throws Exception { PurRepository repo = (PurRepository) repository; DatabaseMeta dbMeta = createDatabaseMeta(EXP_DBMETA_NAME); repository.save(dbMeta, VERSION_COMMENT_V1, null); Map<RepositoryObjectType, List<? extends SharedObjectInterface>> sharedObjectsByType = new HashMap<RepositoryObjectType, List<? extends SharedObjectInterface>>(); repo.readSharedObjects(sharedObjectsByType, RepositoryObjectType.DATABASE); assertNotNull(sharedObjectsByType); @SuppressWarnings("unchecked") List<DatabaseMeta> databaseMetas = (List<DatabaseMeta>) sharedObjectsByType .get(RepositoryObjectType.DATABASE); assertNotNull(databaseMetas); assertEquals(1, databaseMetas.size()); DatabaseMeta dbMetaResult = databaseMetas.get(0); assertNotNull(dbMetaResult); assertEquals(dbMeta, dbMetaResult); repository.deleteDatabaseMeta(EXP_DBMETA_NAME); } @Test public void testLoadSharedObjects_slaves() throws Exception { PurRepository repo = (PurRepository) repository; SlaveServer slave = createSlaveServer(""); //$NON-NLS-1$ repository.save(slave, VERSION_COMMENT_V1, null); Map<RepositoryObjectType, List<? extends SharedObjectInterface>> sharedObjectsByType = new HashMap<RepositoryObjectType, List<? extends SharedObjectInterface>>(); repo.readSharedObjects(sharedObjectsByType, RepositoryObjectType.SLAVE_SERVER); assertNotNull(sharedObjectsByType); @SuppressWarnings("unchecked") List<SlaveServer> slaveServers = (List<SlaveServer>) sharedObjectsByType .get(RepositoryObjectType.SLAVE_SERVER); assertNotNull(slaveServers); assertEquals(1, slaveServers.size()); SlaveServer slaveResult = slaveServers.get(0); assertNotNull(slaveResult); assertEquals(slave, slaveResult); repository.deleteSlave(slave.getObjectId()); } @Test public void testLoadSharedObjects_partitions() throws Exception { PurRepository repo = (PurRepository) repository; PartitionSchema partSchema = createPartitionSchema(""); //$NON-NLS-1$ repository.save(partSchema, VERSION_COMMENT_V1, null); Map<RepositoryObjectType, List<? extends SharedObjectInterface>> sharedObjectsByType = new HashMap<RepositoryObjectType, List<? extends SharedObjectInterface>>(); repo.readSharedObjects(sharedObjectsByType, RepositoryObjectType.PARTITION_SCHEMA); assertNotNull(sharedObjectsByType); @SuppressWarnings("unchecked") List<PartitionSchema> partitionSchemas = (List<PartitionSchema>) sharedObjectsByType .get(RepositoryObjectType.PARTITION_SCHEMA); assertNotNull(partitionSchemas); assertEquals(1, partitionSchemas.size()); PartitionSchema partitionSchemaResult = partitionSchemas.get(0); assertNotNull(partitionSchemaResult); assertEquals(partSchema, partitionSchemaResult); repository.deletePartitionSchema(partSchema.getObjectId()); } @Test public void testNewNonAmbiguousNaming() throws Exception { PurRepository repo = (PurRepository) repository; System.setProperty("KETTLE_COMPATIBILITY_PUR_OLD_NAMING_MODE", "N"); PartitionSchema partSchema1 = createPartitionSchema("find.me"); //$NON-NLS-1$ PartitionSchema partSchema2 = createPartitionSchema("find|me"); //$NON-NLS-1$ repository.save(partSchema1, VERSION_COMMENT_V1, null); repository.save(partSchema2, VERSION_COMMENT_V1, null); Map<RepositoryObjectType, List<? extends SharedObjectInterface>> sharedObjectsByType = new HashMap<RepositoryObjectType, List<? extends SharedObjectInterface>>(); repo.readSharedObjects(sharedObjectsByType, RepositoryObjectType.PARTITION_SCHEMA); List<PartitionSchema> partitionSchemas = (List<PartitionSchema>) sharedObjectsByType .get(RepositoryObjectType.PARTITION_SCHEMA); assertEquals(2, partitionSchemas.size()); System.setProperty("KETTLE_COMPATIBILITY_PUR_OLD_NAMING_MODE", "Y"); PartitionSchema partSchema3 = createPartitionSchema("another.one"); //$NON-NLS-1$ PartitionSchema partSchema4 = createPartitionSchema("another|one"); //$NON-NLS-1$ repository.save(partSchema3, VERSION_COMMENT_V1, null); repository.save(partSchema4, VERSION_COMMENT_V1, null); sharedObjectsByType = new HashMap<RepositoryObjectType, List<? extends SharedObjectInterface>>(); repo.readSharedObjects(sharedObjectsByType, RepositoryObjectType.PARTITION_SCHEMA); partitionSchemas = (List<PartitionSchema>) sharedObjectsByType.get(RepositoryObjectType.PARTITION_SCHEMA); assertEquals(3, partitionSchemas.size()); } @Test public void testLoadSharedObjects_clusters() throws Exception { PurRepository repo = (PurRepository) repository; ClusterSchema clusterSchema = createClusterSchema(EXP_CLUSTER_SCHEMA_NAME); repository.save(clusterSchema, VERSION_COMMENT_V1, null); Map<RepositoryObjectType, List<? extends SharedObjectInterface>> sharedObjectsByType = new HashMap<RepositoryObjectType, List<? extends SharedObjectInterface>>(); repo.readSharedObjects(sharedObjectsByType, RepositoryObjectType.CLUSTER_SCHEMA); assertNotNull(sharedObjectsByType); @SuppressWarnings("unchecked") List<ClusterSchema> clusterSchemas = (List<ClusterSchema>) sharedObjectsByType .get(RepositoryObjectType.CLUSTER_SCHEMA); assertNotNull(clusterSchemas); assertEquals(1, clusterSchemas.size()); ClusterSchema clusterSchemaResult = clusterSchemas.get(0); assertNotNull(clusterSchemaResult); assertEquals(clusterSchema, clusterSchemaResult); repository.deleteClusterSchema(clusterSchema.getObjectId()); } @Test public void testLoadSharedObjects_databases_and_clusters() throws Exception { PurRepository repo = (PurRepository) repository; DatabaseMeta dbMeta = createDatabaseMeta(EXP_DBMETA_NAME); repository.save(dbMeta, VERSION_COMMENT_V1, null); ClusterSchema clusterSchema = createClusterSchema(EXP_CLUSTER_SCHEMA_NAME); repository.save(clusterSchema, VERSION_COMMENT_V1, null); Map<RepositoryObjectType, List<? extends SharedObjectInterface>> sharedObjectsByType = new HashMap<RepositoryObjectType, List<? extends SharedObjectInterface>>(); repo.readSharedObjects(sharedObjectsByType, RepositoryObjectType.CLUSTER_SCHEMA, RepositoryObjectType.DATABASE); assertNotNull(sharedObjectsByType); assertEquals(2, sharedObjectsByType.size()); @SuppressWarnings("unchecked") List<DatabaseMeta> databaseMetas = (List<DatabaseMeta>) sharedObjectsByType .get(RepositoryObjectType.DATABASE); assertNotNull(databaseMetas); assertEquals(1, databaseMetas.size()); DatabaseMeta dbMetaResult = databaseMetas.get(0); assertNotNull(dbMetaResult); assertEquals(dbMeta, dbMetaResult); @SuppressWarnings("unchecked") List<ClusterSchema> clusterSchemas = (List<ClusterSchema>) sharedObjectsByType .get(RepositoryObjectType.CLUSTER_SCHEMA); assertNotNull(clusterSchemas); assertEquals(1, clusterSchemas.size()); ClusterSchema clusterSchemaResult = clusterSchemas.get(0); assertNotNull(clusterSchemaResult); assertEquals(clusterSchema, clusterSchemaResult); repository.deleteDatabaseMeta(EXP_DBMETA_NAME); repository.deleteClusterSchema(clusterSchema.getObjectId()); } private class MockProgressMonitorListener implements ProgressMonitorListener { public void beginTask(String arg0, int arg1) { } public void done() { } public boolean isCanceled() { return false; } public void setTaskName(String arg0) { } public void subTask(String arg0) { } public void worked(int arg0) { } } private class MockRepositoryExportParser extends DefaultHandler2 { private List<String> nodeNames = new ArrayList<String>(); private SAXParseException fatalError; private List<String> nodesToCapture = Arrays.asList("repository", "transformations", "transformation", "jobs", "job"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { // Only capture nodes we care about if (nodesToCapture.contains(qName)) { nodeNames.add(qName); } } @Override public void fatalError(SAXParseException e) throws SAXException { fatalError = e; } public List<String> getNodesWithName(String name) { List<String> nodes = new ArrayList<String>(); for (String node : nodeNames) { if (node.equals(name)) { nodes.add(name); } } return nodes; } public List<String> getNodeNames() { return nodeNames; } public SAXParseException getFatalError() { return fatalError; } } @Ignore @Test public void testExport() throws Exception { final String exportFileName = new File("test.export").getAbsolutePath(); //$NON-NLS-1$ RepositoryDirectoryInterface rootDir = initRepo(); String uniqueTransName = EXP_TRANS_NAME.concat(EXP_DBMETA_NAME); TransMeta transMeta = createTransMeta(EXP_DBMETA_NAME); // Create a database association DatabaseMeta dbMeta = createDatabaseMeta(EXP_DBMETA_NAME); repository.save(dbMeta, VERSION_COMMENT_V1, null); TableInputMeta tableInputMeta = new TableInputMeta(); tableInputMeta.setDatabaseMeta(dbMeta); transMeta.addStep(new StepMeta(EXP_TRANS_STEP_1_NAME, tableInputMeta)); RepositoryDirectoryInterface transDir = rootDir.findDirectory(DIR_TRANSFORMATIONS); repository.save(transMeta, VERSION_COMMENT_V1, null); deleteStack.push(transMeta); // So this transformation is cleaned up afterward assertNotNull(transMeta.getObjectId()); ObjectRevision version = transMeta.getObjectRevision(); assertNotNull(version); assertTrue(hasVersionWithComment(transMeta, VERSION_COMMENT_V1)); assertTrue(repository.exists(uniqueTransName, transDir, RepositoryObjectType.TRANSFORMATION)); JobMeta jobMeta = createJobMeta(EXP_JOB_NAME); RepositoryDirectoryInterface jobsDir = rootDir.findDirectory(DIR_JOBS); repository.save(jobMeta, VERSION_COMMENT_V1, null); deleteStack.push(jobMeta); assertNotNull(jobMeta.getObjectId()); version = jobMeta.getObjectRevision(); assertNotNull(version); assertTrue(hasVersionWithComment(jobMeta, VERSION_COMMENT_V1)); assertTrue(repository.exists(EXP_JOB_NAME, jobsDir, RepositoryObjectType.JOB)); try { repository.getExporter().exportAllObjects(new MockProgressMonitorListener(), exportFileName, null, "all"); //$NON-NLS-1$ FileObject exportFile = KettleVFS.getFileObject(exportFileName); assertNotNull(exportFile); MockRepositoryExportParser parser = new MockRepositoryExportParser(); SAXParserFactory.newInstance().newSAXParser().parse(KettleVFS.getInputStream(exportFile), parser); if (parser.getFatalError() != null) { throw parser.getFatalError(); } assertNotNull("No nodes found in export", parser.getNodeNames()); //$NON-NLS-1$ assertTrue("No nodes found in export", !parser.getNodeNames().isEmpty()); //$NON-NLS-1$ assertEquals("Incorrect number of nodes", 5, parser.getNodeNames().size()); //$NON-NLS-1$ assertEquals("Incorrect number of transformations", 1, parser.getNodesWithName("transformation").size()); //$NON-NLS-1$ //$NON-NLS-2$ assertEquals("Incorrect number of jobs", 1, parser.getNodesWithName("job").size()); //$NON-NLS-2$ //$NON-NLS-2$ } finally { KettleVFS.getFileObject(exportFileName).delete(); } } @Ignore @Test public void testVersionDate() throws Exception { RepositoryDirectoryInterface rootDir = initRepo(); String uniqueTransName = EXP_TRANS_NAME.concat(EXP_DBMETA_NAME); TransMeta transMeta = createTransMeta(EXP_DBMETA_NAME); // Create a database association DatabaseMeta dbMeta = createDatabaseMeta(EXP_DBMETA_NAME); repository.save(dbMeta, VERSION_COMMENT_V1, null); TableInputMeta tableInputMeta = new TableInputMeta(); tableInputMeta.setDatabaseMeta(dbMeta); transMeta.addStep(new StepMeta(EXP_TRANS_STEP_1_NAME, tableInputMeta)); RepositoryDirectoryInterface transDir = rootDir.findDirectory(DIR_TRANSFORMATIONS); Calendar cal = Calendar.getInstance(Locale.US); SimpleDateFormat df = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.US); cal.setTime(df.parse("Wed, 4 Jul 2001 12:08:56 -0700")); repository.save(transMeta, VERSION_COMMENT_V1, null, null, true); repository.save(transMeta, VERSION_COMMENT_V1 + "2", cal, null, true); deleteStack.push(transMeta); // So this transformation is cleaned up afterward assertNotNull(transMeta.getObjectId()); ObjectRevision version = transMeta.getObjectRevision(); assertNotNull(version); assertTrue(hasVersionWithComment(transMeta, VERSION_COMMENT_V1)); assertTrue(hasVersionWithCal(transMeta, cal)); assertTrue(repository.exists(uniqueTransName, transDir, RepositoryObjectType.TRANSFORMATION)); JobMeta jobMeta = createJobMeta(EXP_JOB_NAME); RepositoryDirectoryInterface jobsDir = rootDir.findDirectory(DIR_JOBS); repository.save(jobMeta, VERSION_COMMENT_V1, null); deleteStack.push(jobMeta); assertNotNull(jobMeta.getObjectId()); version = jobMeta.getObjectRevision(); assertNotNull(version); assertTrue(hasVersionWithComment(jobMeta, VERSION_COMMENT_V1)); assertTrue(repository.exists(EXP_JOB_NAME, jobsDir, RepositoryObjectType.JOB)); } @Test public void testMetaStoreBasics() throws MetaStoreException { IMetaStore metaStore = repository.getMetaStore(); assertNotNull(metaStore); MetaStoreTestBase base = new MetaStoreTestBase(); base.testFunctionality(metaStore); } @Test public void testMetaStoreNamespaces() throws MetaStoreException { IMetaStore metaStore = repository.getMetaStore(); assertNotNull(metaStore); // We start with a clean slate, only the pentaho namespace // assertEquals(1, metaStore.getNamespaces().size()); String ns = PentahoDefaults.NAMESPACE; assertEquals(true, metaStore.namespaceExists(ns)); metaStore.deleteNamespace(ns); assertEquals(false, metaStore.namespaceExists(ns)); assertEquals(0, metaStore.getNamespaces().size()); metaStore.createNamespace(ns); assertEquals(true, metaStore.namespaceExists(ns)); List<String> namespaces = metaStore.getNamespaces(); assertEquals(1, namespaces.size()); assertEquals(ns, namespaces.get(0)); try { metaStore.createNamespace(ns); fail("Exception expected when a namespace already exists and where we try to create it again"); } catch (MetaStoreNamespaceExistsException e) { // OK, we expected this. } metaStore.deleteNamespace(ns); assertEquals(false, metaStore.namespaceExists(ns)); assertEquals(0, metaStore.getNamespaces().size()); } @Test public void testMetaStoreElementTypes() throws MetaStoreException { IMetaStore metaStore = repository.getMetaStore(); assertNotNull(metaStore); String ns = PentahoDefaults.NAMESPACE; // We start with a clean slate... // assertEquals(1, metaStore.getNamespaces().size()); assertEquals(true, metaStore.namespaceExists(ns)); // Now create an element type // IMetaStoreElementType elementType = metaStore.newElementType(ns); elementType.setName(PentahoDefaults.KETTLE_DATA_SERVICE_ELEMENT_TYPE_NAME); elementType.setDescription(PentahoDefaults.KETTLE_DATA_SERVICE_ELEMENT_TYPE_DESCRIPTION); metaStore.createElementType(ns, elementType); IMetaStoreElementType verifyElementType = metaStore.getElementType(ns, elementType.getId()); assertEquals(PentahoDefaults.KETTLE_DATA_SERVICE_ELEMENT_TYPE_NAME, verifyElementType.getName()); assertEquals(PentahoDefaults.KETTLE_DATA_SERVICE_ELEMENT_TYPE_DESCRIPTION, verifyElementType.getDescription()); verifyElementType = metaStore.getElementTypeByName(ns, PentahoDefaults.KETTLE_DATA_SERVICE_ELEMENT_TYPE_NAME); assertEquals(PentahoDefaults.KETTLE_DATA_SERVICE_ELEMENT_TYPE_NAME, verifyElementType.getName()); assertEquals(PentahoDefaults.KETTLE_DATA_SERVICE_ELEMENT_TYPE_DESCRIPTION, verifyElementType.getDescription()); // Get the list of element type ids. // List<String> ids = metaStore.getElementTypeIds(ns); assertNotNull(ids); assertEquals(1, ids.size()); assertEquals(elementType.getId(), ids.get(0)); // Verify that we can't delete the namespace since it has content in it! // try { metaStore.deleteNamespace(ns); fail("The namespace deletion didn't cause an exception because there are still an element type in it"); } catch (MetaStoreDependenciesExistsException e) { assertNotNull(e.getDependencies()); assertEquals(1, e.getDependencies().size()); assertEquals(elementType.getId(), e.getDependencies().get(0)); } metaStore.deleteElementType(ns, elementType); assertEquals(0, metaStore.getElementTypes(ns).size()); metaStore.deleteNamespace(ns); } @Test public void testMetaStoreElements() throws MetaStoreException { // Set up a namespace // String ns = PentahoDefaults.NAMESPACE; IMetaStore metaStore = repository.getMetaStore(); if (!metaStore.namespaceExists(ns)) { metaStore.createNamespace(ns); } // And an element type // IMetaStoreElementType elementType = metaStore.newElementType(ns); elementType.setName(PentahoDefaults.KETTLE_DATA_SERVICE_ELEMENT_TYPE_NAME); elementType.setDescription(PentahoDefaults.KETTLE_DATA_SERVICE_ELEMENT_TYPE_DESCRIPTION); metaStore.createElementType(ns, elementType); // Now we play with elements... // IMetaStoreElement oneElement = populateElement(metaStore, elementType, "Element One"); metaStore.createElement(ns, elementType, oneElement); IMetaStoreElement verifyOneElement = metaStore.getElement(ns, elementType, oneElement.getId()); assertNotNull(verifyOneElement); validateElement(verifyOneElement, "Element One"); assertEquals(1, metaStore.getElements(ns, elementType).size()); IMetaStoreElement twoElement = populateElement(metaStore, elementType, "Element Two"); metaStore.createElement(ns, elementType, twoElement); IMetaStoreElement verifyTwoElement = metaStore.getElement(ns, elementType, twoElement.getId()); assertNotNull(verifyTwoElement); assertEquals(2, metaStore.getElements(ns, elementType).size()); try { metaStore.deleteElementType(ns, elementType); fail("Delete element type failed to properly detect element dependencies"); } catch (MetaStoreDependenciesExistsException e) { List<String> ids = e.getDependencies(); assertEquals(2, ids.size()); assertTrue(ids.contains(oneElement.getId())); assertTrue(ids.contains(twoElement.getId())); } metaStore.deleteElement(ns, elementType, oneElement.getId()); assertEquals(1, metaStore.getElements(ns, elementType).size()); metaStore.deleteElement(ns, elementType, twoElement.getId()); assertEquals(0, metaStore.getElements(ns, elementType).size()); } protected IMetaStoreElement populateElement(IMetaStore metaStore, IMetaStoreElementType elementType, String name) throws MetaStoreException { IMetaStoreElement element = metaStore.newElement(); element.setElementType(elementType); element.setName(name); for (int i = 1; i <= 5; i++) { element.addChild(metaStore.newAttribute("id " + i, "value " + i)); } IMetaStoreAttribute subAttr = metaStore.newAttribute("sub-attr", null); for (int i = 101; i <= 110; i++) { subAttr.addChild(metaStore.newAttribute("sub-id " + i, "sub-value " + i)); } element.addChild(subAttr); return element; } protected void validateElement(IMetaStoreElement element, String name) throws MetaStoreException { assertEquals(name, element.getName()); assertEquals(6, element.getChildren().size()); for (int i = 1; i <= 5; i++) { IMetaStoreAttribute child = element.getChild("id " + i); assertEquals("value " + i, child.getValue()); } IMetaStoreAttribute subAttr = element.getChild("sub-attr"); assertNotNull(subAttr); assertEquals(10, subAttr.getChildren().size()); for (int i = 101; i <= 110; i++) { IMetaStoreAttribute child = subAttr.getChild("sub-id " + i); assertNotNull(child); assertEquals("sub-value " + i, child.getValue()); } } @Test public void doesNotChangeFileWhenFailsToRename_slaves() throws Exception { final SlaveServer server1 = new SlaveServer(); final SlaveServer server2 = new SlaveServer(); try { testDoesNotChangeFileWhenFailsToRename(server1, server2, new Callable<RepositoryElementInterface>() { @Override public RepositoryElementInterface call() throws Exception { return repository.loadSlaveServer(server2.getObjectId(), null); } }); } finally { repository.deleteSlave(server1.getObjectId()); repository.deleteSlave(server2.getObjectId()); } } @Test public void doesNotChangeFileWhenFailsToRename_clusters() throws Exception { final ClusterSchema schema1 = new ClusterSchema(); final ClusterSchema schema2 = new ClusterSchema(); try { testDoesNotChangeFileWhenFailsToRename(schema1, schema2, new Callable<RepositoryElementInterface>() { @Override public RepositoryElementInterface call() throws Exception { return repository.loadClusterSchema(schema2.getObjectId(), null, null); } }); } finally { repository.deleteClusterSchema(schema1.getObjectId()); repository.deleteClusterSchema(schema2.getObjectId()); } } @Test public void doesNotChangeFileWhenFailsToRename_partitions() throws Exception { final PartitionSchema schema1 = new PartitionSchema(); final PartitionSchema schema2 = new PartitionSchema(); try { testDoesNotChangeFileWhenFailsToRename(schema1, schema2, new Callable<RepositoryElementInterface>() { @Override public RepositoryElementInterface call() throws Exception { return repository.loadPartitionSchema(schema2.getObjectId(), null); } }); } finally { repository.deletePartitionSchema(schema1.getObjectId()); repository.deletePartitionSchema(schema2.getObjectId()); } } private void testDoesNotChangeFileWhenFailsToRename(RepositoryElementInterface element1, RepositoryElementInterface element2, Callable<RepositoryElementInterface> loader) throws Exception { final String name1 = "name1"; final String name2 = "name2"; element1.setName(name1); element2.setName(name2); repository.save(element1, "", null); repository.save(element2, "", null); element2.setName(name1); try { repository.save(element2, "", null, true); fail("A naming conflict should occur"); } catch (KettleException e) { // expected to be thrown element2.setName(name2); } RepositoryElementInterface loaded = loader.call(); assertEquals(element2, loaded); } @Test public void getObjectInformation_IsDeletedFlagSet_Trans() throws Exception { testDeletedFlagForObject(new Callable<RepositoryElementInterface>() { @Override public RepositoryElementInterface call() throws Exception { TransMeta transMeta = new TransMeta(); transMeta.setName("testTransMeta"); return transMeta; } }); } @Test public void getObjectInformation_IsDeletedFlagSet_Job() throws Exception { testDeletedFlagForObject(new Callable<RepositoryElementInterface>() { @Override public RepositoryElementInterface call() throws Exception { JobMeta jobMeta = new JobMeta(); jobMeta.setName("testJobMeta"); return jobMeta; } }); } private void testDeletedFlagForObject(Callable<RepositoryElementInterface> elementProvider) throws Exception { TransDelegate transDelegate = new TransDelegate(repository, repo); JobDelegate jobDelegate = new JobDelegate(repository, repo); FieldUtils.writeField(repository, "transDelegate", transDelegate, true); FieldUtils.writeField(repository, "jobDelegate", jobDelegate, true); RepositoryElementInterface element = elementProvider.call(); RepositoryDirectoryInterface directory = repository .findDirectory(element.getRepositoryDirectory().getPath()); element.setRepositoryDirectory(directory); repository.save(element, null, null); assertNotNull("Element was saved", element.getObjectId()); RepositoryObject information; information = repository.getObjectInformation(element.getObjectId(), element.getRepositoryElementType()); assertNotNull(information); assertFalse(information.isDeleted()); repository.deleteTransformation(element.getObjectId()); assertNotNull("Element was moved to Trash", repo.getFileById(element.getObjectId().getId())); information = repository.getObjectInformation(element.getObjectId(), element.getRepositoryElementType()); assertNotNull(information); assertTrue(information.isDeleted()); } @Test public void getObjectInformation_InvalidRepositoryId_ExceptionIsHandled() throws Exception { IUnifiedRepository unifiedRepository = mock(IUnifiedRepository.class); when(unifiedRepository.getFileById(any(Serializable.class))).thenThrow(new RuntimeException("unknown id")); ((PurRepository) repository).setTest(unifiedRepository); RepositoryObject information = repository.getObjectInformation(new StringObjectId("invalid id"), RepositoryObjectType.JOB); assertNull("Should return null if file was not found", information); } @Test public void getObjectInformation_InvalidRepositoryId_NullIsHandled() throws Exception { IUnifiedRepository unifiedRepository = mock(IUnifiedRepository.class); when(unifiedRepository.getFileById(any(Serializable.class))).thenReturn(null); ((PurRepository) repository).setTest(unifiedRepository); RepositoryObject information = repository.getObjectInformation(new StringObjectId("invalid id"), RepositoryObjectType.JOB); assertNull("Should return null if file was not found", information); } @Test public void testRenameJob() { String[] jobNamesArraysBeforeRename = { "Job 1", "Job 2" }; String[] jobNamesArraysAfterRename = { "Job 1", "Job 3" }; RepositoryElementInterface job1 = new JobMeta(); job1.setName(jobNamesArraysBeforeRename[0]); RepositoryElementInterface job2 = new JobMeta(); job2.setName(jobNamesArraysBeforeRename[1]); try { RepositoryDirectoryInterface directory = repository.findDirectory("public"); job1.setRepositoryDirectory(directory); job2.setRepositoryDirectory(directory); repository.save(job1, VERSION_COMMENT_V1, null); repository.save(job2, VERSION_COMMENT_V1, null); assertArrayEquals(repository.getJobNames(directory.getObjectId(), false), jobNamesArraysBeforeRename); repository.renameJob(job2.getObjectId(), job1.getRepositoryDirectory(), jobNamesArraysAfterRename[1]); assertArrayEquals(repository.getJobNames(directory.getObjectId(), false), jobNamesArraysAfterRename); } catch (KettleException e) { e.printStackTrace(); fail("Unexpected error"); } try { repository.renameJob(job2.getObjectId(), job1.getRepositoryDirectory(), jobNamesArraysBeforeRename[0]); fail("A naming conflict should occur"); } catch (KettleException e) { //expected } } }