/*********************************************************************** * This file is part of iDempiere ERP Open Source * * http://www.idempiere.org * * * * Copyright (C) Contributors * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301, USA. * * * * Contributors: * * - hengsin * **********************************************************************/ package org.idempiere.test.performance; import static org.assertj.core.api.Assertions.assertThatNoException; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.math.BigDecimal; import java.net.URL; import java.sql.Timestamp; import java.util.List; import java.util.Optional; import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import org.adempiere.base.Core; import org.adempiere.base.DefaultPaymentExporterFactory; import org.adempiere.base.IAddressValidationFactory; import org.adempiere.base.IBankStatementLoaderFactory; import org.adempiere.base.IBankStatementMatcherFactory; import org.adempiere.base.IColumnCallout; import org.adempiere.base.IDisplayTypeFactory; import org.adempiere.base.IPaymentExporterFactory; import org.adempiere.base.IReplenishFactory; import org.adempiere.base.IResourceFinder; import org.adempiere.base.LookupFactoryHelper; import org.adempiere.base.ServiceQuery; import org.adempiere.model.IAddressValidation; import org.adempiere.model.IShipmentProcessor; import org.adempiere.model.ITaxProvider; import org.adempiere.model.MShipperFacade; import org.adempiere.model.ProductPriceValidator; import org.compiere.acct.Doc; import org.compiere.acct.DocManager; import org.compiere.db.AdempiereDatabase; import org.compiere.db.Database; import org.compiere.impexp.BankStatementLoaderInterface; import org.compiere.impexp.BankStatementMatcherInterface; import org.compiere.impexp.OFXFileBankStatementLoader; import org.compiere.model.Callout; import org.compiere.model.GridFieldVO; import org.compiere.model.GridTabVO; import org.compiere.model.GridWindowVO; import org.compiere.model.IArchiveStore; import org.compiere.model.IAttachmentStore; import org.compiere.model.IImageStore; import org.compiere.model.I_AD_Table; import org.compiere.model.I_M_InventoryLine; import org.compiere.model.Lookup; import org.compiere.model.MAcctSchema; import org.compiere.model.MAddressValidation; import org.compiere.model.MBPartner; import org.compiere.model.MBankAccountProcessor; import org.compiere.model.MClientInfo; import org.compiere.model.MColumn; import org.compiere.model.MDocType; import org.compiere.model.MInvoice; import org.compiere.model.MInvoiceLine; import org.compiere.model.MOrder; import org.compiere.model.MProduct; import org.compiere.model.MRefTable; import org.compiere.model.MShipper; import org.compiere.model.MStorageProvider; import org.compiere.model.MTable; import org.compiere.model.MTaxProvider; import org.compiere.model.MTest; import org.compiere.model.MWarehouse; import org.compiere.model.MZoomCondition; import org.compiere.model.ModelValidator; import org.compiere.model.PO; import org.compiere.model.PaymentProcessor; import org.compiere.model.Query; import org.compiere.model.StandardTaxProvider; import org.compiere.model.X_C_AddressValidationCfg; import org.compiere.model.X_C_TaxProviderCfg; import org.compiere.print.MPrintFormat; import org.compiere.process.BPartnerValidate; import org.compiere.process.DocAction; import org.compiere.process.DocumentEngine; import org.compiere.process.ProcessCall; import org.compiere.process.ProcessInfo; import org.compiere.util.CCache; import org.compiere.util.CacheInterface; import org.compiere.util.CacheMgt; import org.compiere.util.DisplayType; import org.compiere.util.Env; import org.compiere.util.GenericPaymentExport; import org.compiere.util.PaymentExport; import org.compiere.util.ReplenishInterface; import org.compiere.util.TimeUtil; import org.compiere.wf.MWorkflow; import org.eevolution.model.CalloutBOM; import org.idempiere.cache.ImmutableIntPOCache; import org.idempiere.fa.service.api.DepreciationFactoryLookupDTO; import org.idempiere.fa.service.api.IDepreciationMethod; import org.idempiere.fa.service.api.IDepreciationMethodFactory; import org.idempiere.test.AbstractTestCase; import org.idempiere.test.DictionaryIDs; import org.idempiere.test.TestActivator; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.parallel.Isolated; /** * * @author hengsin * */ @Isolated public class CacheTest extends AbstractTestCase { private static final int ORDER_HEADER_PRINT_FORMAT_ID = 118; private static final int SHIPMENT_HEADER_PRINT_FORMAT_ID = 122; public CacheTest() { } @Test /** * https://idempiere.atlassian.net/browse/IDEMPIERE-2698 */ public void testZoomConditionCache() { MZoomCondition[] conditions1 = MZoomCondition.getConditions(MOrder.Table_ID); assertTrue(conditions1 != null && conditions1.length > 0); MZoomCondition[] conditions2 = MZoomCondition.getConditions(MOrder.Table_ID); assertTrue(conditions2 != null && conditions2.length > 0); assertTrue(conditions1 == conditions2); CacheMgt.get().reset(); MZoomCondition[] conditions3 = MZoomCondition.getConditions(MOrder.Table_ID); assertTrue(conditions3 != null && conditions3.length == conditions1.length); assertTrue(conditions1 != conditions3); } @Test /** * https://idempiere.atlassian.net/browse/IDEMPIERE-2699 */ public void testTableCache() { MTable table = MTable.get(Env.getCtx(), MOrder.Table_ID); //find table cache instance CCache tblCache = findByTableNameAndKey(MTable.Table_Name, MOrder.Table_ID); if (tblCache == null) fail("Table cache instance missing"); long hit = tblCache.getHit(); MColumn column = table.getColumn(MOrder.COLUMNNAME_C_Order_ID); @SuppressWarnings("unused") I_AD_Table table2 = column.getAD_Table(); assertEquals(hit+1, tblCache.getHit()); //M_Warehouse of Client table = MTable.get(Env.getCtx(), MWarehouse.Table_ID); MRefTable refTable = MRefTable.get(Env.getCtx(), 197); tblCache = findByTableNameAndKey(MTable.Table_Name, MWarehouse.Table_ID); if (tblCache == null) fail("Table cache instance missing"); hit = tblCache.getHit(); table2 = refTable.getAD_Table(); assertEquals(hit+1, tblCache.getHit()); } @SuppressWarnings({"unchecked"}) @Test public void testPOCacheAfterUpdate() throws InterruptedException { int mulch = 137; int oak = 123; //init cache MProduct p1 = MProduct.get(Env.getCtx(), mulch); CCache pc = (CCache) findByTableNameAndKey(MProduct.Table_Name, mulch); if (pc == null) fail("Product cache instance missing"); //second get, hit should increase long hit = pc.getHit(); p1 = MProduct.get(Env.getCtx(), mulch); assertEquals(mulch, p1.getM_Product_ID()); assertTrue(pc.getHit() > hit, "Second get of product Mulch, cache hit should increase"); //first get for p2, miss should increase long miss = pc.getMiss(); MProduct p2 = MProduct.get(Env.getCtx(), oak); assertEquals(oak, p2.getM_Product_ID()); assertTrue(pc.getMiss() > miss, "First get of product Oak, cache miss should increase"); //second get for p2, hit should increase hit = pc.getHit(); p2 = MProduct.get(Env.getCtx(), oak); assertEquals(oak, p2.getM_Product_ID()); assertTrue(pc.getHit() > hit, "Second get of product Oak, cache hit should increase"); String oakDescription = p2.getDescription(); p2 = new MProduct(Env.getCtx(), p2, getTrxName()); p2.setDescription("Test Update @ " + System.currentTimeMillis()); p2.saveEx(); commit(); //get after p2 update, miss should increase //wait 500ms since cache reset after update is async Thread.sleep(500); miss = pc.getMiss(); p2 = MProduct.get(Env.getCtx(), oak); assertEquals(oak, p2.getM_Product_ID()); assertTrue(pc.getMiss() > miss, "Get of product Oak after update of product Oak, cache miss should increase. before="+miss+" after="+pc.getMiss()); //cache for p1 not effected by p2 update, hit should increase hit = pc.getHit(); p1 = MProduct.get(Env.getCtx(), mulch); assertEquals(mulch, p1.getM_Product_ID()); assertTrue(pc.getHit() > hit, "Get of product Mulch after update of product Oak, cache hit should increase. before="+hit+" after="+pc.getHit()); //create p3 to test delete MProduct p3 = new MProduct(Env.getCtx(), 0, getTrxName()); String name = "Test@"+System.currentTimeMillis(); p3.setValue(name); p3.setName(name); p3.setM_Product_Category_ID(p1.getM_Product_Category_ID()); p3.setC_UOM_ID(p1.getC_UOM_ID()); p3.setC_TaxCategory_ID(p1.getC_TaxCategory_ID()); p3.saveEx(); p3.deleteEx(true); commit(); //cache for p2 not effected by p3 delete, hit should increase hit = pc.getHit(); p2 = MProduct.get(Env.getCtx(), oak); assertEquals(oak, p2.getM_Product_ID()); assertTrue(pc.getHit() > hit, "Get of product Oak after delete of product Mulch, cache hit should increase"); //test update when cache is empty CacheMgt.get().reset(); p2 = new MProduct(Env.getCtx(), p2, getTrxName()); p2.setDescription("Test1@"+System.currentTimeMillis()); p2.saveEx(); rollback(); //revert description update p2 = new MProduct(Env.getCtx(), oak, null); p2.setDescription(oakDescription); p2.saveEx(); } @Test public void testServices() { //IResourceFinder TestActivator.context.registerService(IResourceFinder.class, new FakeResourceFinder(), null); IResourceFinder resourceFinder = Core.getResourceFinder(); assertNotNull(resourceFinder, "Can't find resource finder service"); String cacheKey = FakeResourceFinder.class.getName(); URL url = Core.getResourceFinder().getResource(cacheKey); assertNotNull(url); String cacheName = "IResourceFinder"; CCache cache = findByNameAndKey(cacheName, cacheKey); assertNotNull(cache, "Can't find cache for " + cacheName); long hit = cache.getHit(); url = Core.getResourceFinder().getResource(cacheKey); assertNotNull(url); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); //IColumnCalloutFactory List callouts = Core.findCallout(I_M_InventoryLine.Table_Name, I_M_InventoryLine.COLUMNNAME_M_Product_ID); assertTrue(callouts.size() > 0, "Can't find callouts for " + I_M_InventoryLine.Table_Name + ", " + I_M_InventoryLine.COLUMNNAME_M_Product_ID); cacheKey = I_M_InventoryLine.Table_Name + "." + I_M_InventoryLine.COLUMNNAME_M_Product_ID; cacheName = "List"; cache = findByNameAndKey(cacheName, cacheKey); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); callouts = Core.findCallout(I_M_InventoryLine.Table_Name, I_M_InventoryLine.COLUMNNAME_M_Product_ID); assertTrue(callouts.size() > 0, "Can't find callouts for " + I_M_InventoryLine.Table_Name + ", " + I_M_InventoryLine.COLUMNNAME_M_Product_ID); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); //ICalloutFactory cacheKey = CalloutBOM.class.getName() + "::" + "parent"; Callout callout = Core.getCallout(CalloutBOM.class.getName(), "parent"); assertNotNull(callout, "Can't find callout for " + cacheKey); cacheName = "ICalloutFactory"; cache = findByNameAndKey(cacheName, cacheKey); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); callout = Core.getCallout(CalloutBOM.class.getName(), "parent"); assertNotNull(callout, "Can't find callout for " + cacheKey); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); //IProcessFactory cacheKey = BPartnerValidate.class.getName(); ProcessCall process = Core.getProcess(cacheKey); assertNotNull(process, "Can't find process for " + cacheKey); cacheName = "IProcessFactory"; cache = findByNameAndKey(cacheName, cacheKey); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); process = Core.getProcess(cacheKey); assertNotNull(process, "Can't find process for " + cacheKey); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); //IModelValidatorFactory cacheKey = ProductPriceValidator.class.getName(); ModelValidator modelValidator = Core.getModelValidator(cacheKey); assertNotNull(modelValidator, "Can't find model validator for " + cacheKey); cacheName = "IModelValidatorFactory"; cache = findByNameAndKey(cacheName, cacheKey); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); modelValidator = Core.getModelValidator(cacheKey); assertNotNull(modelValidator, "Can't find model validator for " + cacheKey); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); //IKeyStore assertNotNull(Core.getKeyStore(), "Can't find key store service"); //second call to check service reference cache is working assertNotNull(Core.getKeyStore(), "Can't find key store service"); //IPaymentProcessorFactory int pp_payflowpro_id = 100; MBankAccountProcessor bankAccountProcessor = MBankAccountProcessor.get(Env.getCtx(), pp_payflowpro_id, pp_payflowpro_id, getTrxName()); assertNotNull(bankAccountProcessor, "Can't load bank account processor for PP_PayFlowPro"); PaymentProcessor paymentProcessor = Core.getPaymentProcessor(bankAccountProcessor, null); assertNotNull(paymentProcessor, "Can't load payment processor for PP_PayFlowPro"); cacheKey = "org.compiere.model.PP_PayFlowPro"; cacheName = "IPaymentProcessorFactory"; cache = findByNameAndKey(cacheName, cacheKey); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); paymentProcessor = Core.getPaymentProcessor(bankAccountProcessor, null); assertNotNull(paymentProcessor, "Can't load payment processor for PP_PayFlowPro"); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); //IBankStatementLoaderFactory TestActivator.context.registerService(IBankStatementLoaderFactory.class, new FakeBankStatementLoaderFactory(), null); cacheKey = OFXFileBankStatementLoader.class.getName(); BankStatementLoaderInterface bankStatementLoader = Core.getBankStatementLoader(cacheKey); assertNotNull(bankStatementLoader, "Can't find BankStatementLoader for " + cacheKey); cacheName = "IBankStatementLoaderFactory"; cache = findByNameAndKey(cacheName, cacheKey); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); bankStatementLoader = Core.getBankStatementLoader(cacheKey); assertNotNull(bankStatementLoader, "Can't find BankStatementLoader for " + cacheKey); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); //IBankStatementMatcherFactory TestActivator.context.registerService(IBankStatementMatcherFactory.class, new FakeBankStatementMatcherFactory(), null); cacheKey = FakeBankStatementMatcherFactory.class.getName(); BankStatementMatcherInterface bankStatementMatcher = Core.getBankStatementMatcher(cacheKey); assertNotNull(bankStatementMatcher, "Can't find bank statement matcher service"); cacheName = "IBankStatementMatcherFactory"; cache = findByNameAndKey(cacheName, cacheKey); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); bankStatementMatcher = Core.getBankStatementMatcher(cacheKey); assertNotNull(bankStatementMatcher, "Can't find bank statement matcher service"); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); //IShipmentProcessorFactory int m_shipper_id=100; MShipperFacade shipperFacade = new MShipperFacade(new MShipper(Env.getCtx(), m_shipper_id, getTrxName())); cacheKey = shipperFacade.getShippingProcessorClass(); cacheName = "IShipmentProcessorFactory"; IShipmentProcessor shipmentProcessor = Core.getShipmentProcessor(shipperFacade); assertNotNull(shipmentProcessor, "Can't find shipment processor"); cache = findByNameAndKey(cacheName, cacheKey); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); shipmentProcessor = Core.getShipmentProcessor(shipperFacade); assertNotNull(shipmentProcessor, "Can't find shipment processor"); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); //IAddressValidationFactory X_C_AddressValidationCfg cfg = new X_C_AddressValidationCfg(Env.getCtx(), 0, getTrxName()); cfg.setHostAddress("10.8.0.1"); cfg.setHostPort(433); cfg.setName("Test Cfg"); cacheKey = FakeAddressValidationFactory.class.getName(); cfg.setAddressValidationClass(cacheKey); cfg.saveEx(); MAddressValidation addressValidation = new MAddressValidation(Env.getCtx(), 0, getTrxName()); addressValidation.setC_AddressValidationCfg_ID(cfg.get_ID()); addressValidation.setConnectionPassword("password"); addressValidation.setName("Test Address Validation"); addressValidation.setUserID("userid"); addressValidation.setSeqNo(10); addressValidation.saveEx(); TestActivator.context.registerService(IAddressValidationFactory.class, new FakeAddressValidationFactory(), null); IAddressValidation addressValidationService = Core.getAddressValidation(addressValidation); assertNotNull(addressValidationService, "Can't find address validation service"); cacheName = "IAddressValidationFactory"; cache = findByNameAndKey(cacheName, cacheKey); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); addressValidationService = Core.getAddressValidation(addressValidation); assertNotNull(addressValidationService, "Can't find address validation service"); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); //ITaxProviderFactory X_C_TaxProviderCfg taxProviderCfg = new X_C_TaxProviderCfg(Env.getCtx(), 0, getTrxName()); taxProviderCfg.setName("Standard Provider Configuration"); taxProviderCfg.setTaxProviderClass(StandardTaxProvider.class.getName()); taxProviderCfg.saveEx(); MTaxProvider taxProvider = new MTaxProvider(Env.getCtx(), 0, getTrxName()); taxProvider.setC_TaxProviderCfg_ID(taxProviderCfg.get_ID()); taxProvider.setName("Standard Provider"); taxProvider.saveEx(); ITaxProvider taxProviderService = Core.getTaxProvider(taxProvider); assertNotNull(taxProviderService, "Can't find tax provider service"); cacheKey = StandardTaxProvider.class.getName(); cacheName = "ITaxProviderFactory"; cache = findByNameAndKey(cacheName, cacheKey); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); taxProviderService = Core.getTaxProvider(taxProvider); assertNotNull(taxProviderService, "Can't find tax provider service"); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); //IReplenishFactory TestActivator.context.registerService(IReplenishFactory.class, new FakeReplenishFactory(), null); cacheKey = FakeReplenishFactory.class.getName(); ReplenishInterface replenishService = Core.getReplenish(cacheKey); assertNotNull(replenishService, "Can't find replenish service"); cacheName = "IReplenishFactory"; cache = findByNameAndKey(cacheName, cacheKey); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); replenishService = Core.getReplenish(cacheKey); assertNotNull(replenishService, "Can't find replenish service"); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); //ScriptEngineFactory TestActivator.context.registerService(ScriptEngineFactory.class, new FakeScriptEngineFactory(), null); cacheKey = FakeScriptEngineFactory.class.getName(); ScriptEngine scriptEngine = Core.getScriptEngine(cacheKey); assertNotNull(scriptEngine, "Can't find script engine service"); cacheName = "ScriptEngineFactory"; cache = findByNameAndKey(cacheName, cacheKey); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); scriptEngine = Core.getScriptEngine(cacheKey); assertNotNull(scriptEngine, "Can't find script engine service"); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); //IPaymentExporterFactory TestActivator.context.registerService(IPaymentExporterFactory.class, new DefaultPaymentExporterFactory(), null); cacheKey = GenericPaymentExport.class.getName(); PaymentExport paymentExportService = Core.getPaymentExporter(cacheKey); assertNotNull(paymentExportService, "Can't find payment exporter service"); cacheName = "IPaymentExporterFactory"; cache = findByNameAndKey(cacheName, cacheKey); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); paymentExportService = Core.getPaymentExporter(cacheKey); assertNotNull(paymentExportService, "Can't find payment exporter service"); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); //IProductPricing assertNotNull(Core.getProductPricing(), "Can't find product pricing service"); //second call to check service reference cache is working assertNotNull(Core.getProductPricing(), "Can't find product pricing service"); //IDepreciationMethodFactory TestActivator.context.registerService(IDepreciationMethodFactory.class, new FakeDepreciationMethodFactory(), null); cacheKey = FakeDepreciationMethodFactory.class.getName(); DepreciationFactoryLookupDTO dto = new DepreciationFactoryLookupDTO(); dto.depreciationType = cacheKey; IDepreciationMethod depreciationMethod = Core.getDepreciationMethod(dto); assertNotNull(depreciationMethod, "Can't find depreciation method service"); cacheName = "IDepreciationMethodFactory"; cache = findByNameAndKey(cacheName, cacheKey); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); depreciationMethod = Core.getDepreciationMethod(dto); assertNotNull(depreciationMethod, "Can't find depreciation method service"); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); //IMessageService assertNotNull(Core.getMessageService(), "Can't find message service"); //second call to check service reference cache is working assertNotNull(Core.getMessageService(), "Can't find message service"); //IClusterService assertNotNull(Core.getClusterService(), "Can't find cluster service"); //second call to check service reference cache is working assertNotNull(Core.getClusterService(), "Can't find cluster service"); //ICacheService assertNotNull(Core.getCacheService(), "Can't find cache service"); //second call to check service reference cache is working assertNotNull(Core.getCacheService(), "Can't find cache service"); //IDictionaryService assertNotNull(Core.getDictionaryService(), "Can't find dictionary service"); //second call to check service reference cache is working assertNotNull(Core.getDictionaryService(), "Can't find dictionary service"); //ILookupFactory int ad_window_id=143; //sales order window int ad_tab_id=187; //sales order line int ad_field_id=1127; //product GridFieldVO gridField = null; Lookup lookup = null; GridWindowVO gridWindow = GridWindowVO.create(1, ad_window_id); Optional optional = gridWindow.Tabs.stream().filter(e -> e.AD_Tab_ID == ad_tab_id).findFirst(); if (optional.isPresent()) { GridTabVO gridTabVO = optional.get(); Optional optional1 = gridTabVO.getFields().stream().filter(e -> e.AD_Field_ID == ad_field_id).findFirst(); if (optional1.isPresent()) { gridField = optional1.get(); } } assertNotNull(gridField, "Can't find grid field"); lookup = LookupFactoryHelper.getLookup(gridField); assertNotNull(lookup, "Can't find lookup service"); cacheName = "ILookupFactory"; cacheKey = null; cache = findByNameAndKey(cacheName, cacheKey); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); lookup = LookupFactoryHelper.getLookup(gridField); assertNotNull(lookup, "Can't find lookup service"); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); hit = cache.getHit(); assertTrue(LookupFactoryHelper.isLookup(gridField), "Lookup should be true for " + gridField.toString()); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); //IDocFactory int C_AcctSchema_ID = MClientInfo.get().getC_AcctSchema1_ID(); cacheKey = C_AcctSchema_ID + "|" + MInvoice.Table_ID; cacheName = "IDocFactory"; MInvoice invoice = new MInvoice(Env.getCtx(), 0, getTrxName()); invoice.setBPartner(MBPartner.get(Env.getCtx(), 117)); // C&W invoice.setC_DocTypeTarget_ID(MDocType.DOCBASETYPE_ARInvoice); invoice.setC_DocType_ID(invoice.getC_DocTypeTarget_ID()); // required to avoid runDocumentActionWorkflow exception invoice.setPaymentRule(MInvoice.PAYMENTRULE_Check); invoice.setC_PaymentTerm_ID(105); // Immediate Timestamp today = TimeUtil.getDay(System.currentTimeMillis()); invoice.setDateInvoiced(today); invoice.setDateAcct(today); invoice.setDocStatus(DocAction.STATUS_Drafted); invoice.setDocAction(DocAction.ACTION_Complete); invoice.saveEx(); MInvoiceLine line1 = new MInvoiceLine(invoice); line1.setLine(10); line1.setC_Charge_ID(100); // Bank Charge line1.setQty(new BigDecimal("1")); line1.setPrice(Env.ONEHUNDRED); line1.saveEx(); ProcessInfo info = MWorkflow.runDocumentActionWorkflow(invoice, DocAction.ACTION_Complete); invoice.load(getTrxName()); assertFalse(info.isError(), info.getSummary()); assertEquals(DocAction.STATUS_Completed, invoice.getDocStatus()); if (!invoice.isPosted()) { String error = DocumentEngine.postImmediate(Env.getCtx(), invoice.getAD_Client_ID(), MInvoice.Table_ID, invoice.get_ID(), true, getTrxName()); assertNull(error, "Error posting invoice: " + error); } MAcctSchema as = MAcctSchema.get(C_AcctSchema_ID); Doc doc = DocManager.getDocument(as, MInvoice.Table_ID, invoice.get_ID(), getTrxName()); assertNotNull(doc, "Failed load acct doc for invoice"); cache = findByNameAndKey(cacheName, cacheKey); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); doc = DocManager.getDocument(as, MInvoice.Table_ID, invoice.get_ID(), getTrxName()); assertNotNull(doc, "Failed load acct doc for invoice"); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); //IDatabase AdempiereDatabase db = Database.getDatabase(Database.DB_POSTGRESQL); assertNotNull(db, "Failed to load db service for " + Database.DB_POSTGRESQL); cacheKey = Database.DB_POSTGRESQL; cacheName = "IDatabase"; cache = findByNameAndKey(cacheName, cacheKey); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); db = Database.getDatabase(Database.DB_POSTGRESQL); assertNotNull(db, "Failed to load db service for " + Database.DB_POSTGRESQL); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); //IArchiveStore ServiceQuery dbServiceQuery = new ServiceQuery(); dbServiceQuery.put("method", "DB"); IArchiveStore archiveStoreService = MStorageProvider.getArchiveStoreService(dbServiceQuery); assertNotNull(archiveStoreService, "Can't find archive store service"); cacheName = "IArchiveStore"; cache = findByNameAndKey(cacheName, dbServiceQuery); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); archiveStoreService = MStorageProvider.getArchiveStoreService(dbServiceQuery); assertNotNull(archiveStoreService, "Can't find archive store service"); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); ServiceQuery fileSystemServiceQuery = new ServiceQuery(); fileSystemServiceQuery.put("method", "FileSystem"); archiveStoreService = MStorageProvider.getArchiveStoreService(fileSystemServiceQuery); assertNotNull(archiveStoreService, "Can't find archive store service"); hit = cache.getHit(); archiveStoreService = MStorageProvider.getArchiveStoreService(fileSystemServiceQuery); assertNotNull(archiveStoreService, "Can't find archive store service"); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); assertTrue(cache.size() == 2, "Size for " + cacheName + " != 2"); //IAttachmentStore IAttachmentStore attachmentStoreService = MStorageProvider.getAttachmentStoreService(dbServiceQuery); assertNotNull(attachmentStoreService, "Can't find attachment store service"); cacheName = "IAttachmentStore"; cache = findByNameAndKey(cacheName, dbServiceQuery); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); attachmentStoreService = MStorageProvider.getAttachmentStoreService(dbServiceQuery); assertNotNull(attachmentStoreService, "Can't find attachment store service"); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); attachmentStoreService = MStorageProvider.getAttachmentStoreService(fileSystemServiceQuery); assertNotNull(attachmentStoreService, "Can't find attachment store service"); hit = cache.getHit(); attachmentStoreService = MStorageProvider.getAttachmentStoreService(fileSystemServiceQuery); assertNotNull(attachmentStoreService, "Can't find attachment store service"); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); assertTrue(cache.size() == 2, "Size for " + cacheName + " != 2"); //IImageStore IImageStore imagetStoreService = MStorageProvider.getImageStoreService(dbServiceQuery); assertNotNull(imagetStoreService, "Can't find image store service"); cacheName = "IImageStore"; cache = findByNameAndKey(cacheName, dbServiceQuery); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); imagetStoreService = MStorageProvider.getImageStoreService(dbServiceQuery); assertNotNull(imagetStoreService, "Can't find image store service"); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); imagetStoreService = MStorageProvider.getImageStoreService(fileSystemServiceQuery); assertNotNull(imagetStoreService, "Can't find image store service"); hit = cache.getHit(); imagetStoreService = MStorageProvider.getImageStoreService(fileSystemServiceQuery); assertNotNull(imagetStoreService, "Can't find image store service"); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); assertTrue(cache.size() == 2, "Size for " + cacheName + " != 2"); //IModelFactory cacheName = "IModelFactory"; cacheKey = MInvoice.Table_Name; Class modelClass = MTable.getClass(cacheKey); assertNotNull(modelClass, "Can't find model class for " + cacheKey); cache = findByNameAndKey(cacheName, cacheKey); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); modelClass = MTable.getClass(cacheKey); assertNotNull(modelClass, "Can't find model class for " + cacheKey); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); //IDisplayTypeFactory TestActivator.context.registerService(IDisplayTypeFactory.class, new FakeDisplayTypeFactory(), null); cacheName = "IDisplayTypeFactory"; boolean isLOB = DisplayType.isLOB(FakeDisplayTypeFactory.DISPLAY_TYPE); assertFalse(isLOB); boolean isText = DisplayType.isText(FakeDisplayTypeFactory.DISPLAY_TYPE); assertTrue(isText); cache = findByNameAndKey(cacheName, FakeDisplayTypeFactory.DISPLAY_TYPE); assertNotNull(cache, "Can't find cache for " + cacheName); hit = cache.getHit(); isText = DisplayType.isText(FakeDisplayTypeFactory.DISPLAY_TYPE); assertTrue(isText); assertTrue(cache.getHit() > hit, "Hit for " + cacheName + " doesn't increase as expected"); } private CCache findByTableNameAndKey(String tableName, Object key) { CacheInterface[] cis = CacheMgt.get().getInstancesAsArray(); for(CacheInterface ci : cis) { if (ci instanceof CCache) { @SuppressWarnings("rawtypes") CCache ccache = (CCache) ci; if (ccache.getName().equals(ccache.getTableName()) && ccache.getTableName().equals(tableName)) { if (ccache.containsKey(key)) { return ccache; } } } } return null; } private CCache findByNameAndKey(String name, Object key) { CacheInterface[] cis = CacheMgt.get().getInstancesAsArray(); for(CacheInterface ci : cis) { if (ci instanceof CCache) { @SuppressWarnings("rawtypes") CCache ccache = (CCache) ci; if (ccache.getName().equals(name)) { if (key != null) { if (ccache.containsKey(key)) { return ccache; } } else { return ccache; } } } } return null; } @Test public void testPrintFormatCacheReset() { MPrintFormat cache = MPrintFormat.get(ORDER_HEADER_PRINT_FORMAT_ID); String description = cache.getDescription(); MPrintFormat cache1 = MPrintFormat.get(SHIPMENT_HEADER_PRINT_FORMAT_ID); MPrintFormat update = new MPrintFormat(Env.getCtx(), cache.get_ID(), null); try { update.setDescription(update.getAD_PrintFormat_UU()); update.saveEx(); //wait for async cache reset try { Thread.sleep(500); } catch (InterruptedException e) { } cache = MPrintFormat.get(ORDER_HEADER_PRINT_FORMAT_ID); assertEquals(update.getDescription(), cache.getDescription(), "Expected cache reset doesn't happens"); //shipment header shouldn't reload since only order header have been updated cache = MPrintFormat.get(SHIPMENT_HEADER_PRINT_FORMAT_ID); assertTrue(cache == cache1, "Unexpected cache reset for print format record that's not being updated"); } finally { update.load((String)null); update.setDescription(description); update.saveEx(); } } private static class MTestCache extends CCache { private static final long serialVersionUID = 1L; private int resetCount = 0; public MTestCache(String name, int capacity) { super(name, capacity); } @Override public int reset() { resetCount++; return super.reset(); } @Override public int reset(int recordId) { resetCount++; return super.reset(recordId); } @Override public void newRecord(int record_ID) { resetCount++; super.newRecord(record_ID); } public int getResetCount() { return resetCount; } public void clearResetCount() { resetCount = 0; } }; @Test public void testSuspendCacheReset() { MTest test1 = new MTest(Env.getCtx(), 0, getTrxName()); MTest test2 = new MTest(Env.getCtx(), 0, getTrxName()); MTest test3 = new MTest(Env.getCtx(), 0, getTrxName()); try { MTestCache cache = new MTestCache(MTest.Table_Name, 10); //test insert and cache reset test1.setName("test1"); test1.saveEx(); test2.setName("test2"); test2.saveEx(); test3.setName("test3"); test3.saveEx(); cache.put(test1.get_ID(), test1); cache.put(test2.get_ID(), test2); cache.put(test3.get_ID(), test3); cache.clearResetCount(); commit(); getTrx().start(); try { Thread.sleep(500); } catch (InterruptedException e) { } assertTrue(cache.getResetCount() > 0, "Cache reset count is zero"); //test update and cache reset test1.setName("test1.1"); test1.saveEx(); test2.setName("test2.1"); test2.saveEx(); test3.setName("test3.1"); test3.saveEx(); cache.put(test1.get_ID(), test1); cache.put(test2.get_ID(), test2); cache.put(test3.get_ID(), test3); cache.clearResetCount(); commit(); getTrx().start(); try { Thread.sleep(500); } catch (InterruptedException e) { } assertTrue(cache.getResetCount() > 0, "Cache reset count is zero"); //test update and cache reset after suspend reset call CacheMgt.get().suspendTableCacheReset(MTest.Table_Name); test1.setName("test1.2"); test1.saveEx(); test2.setName("test2.2"); test2.saveEx(); test3.setName("test3.2"); test3.saveEx(); cache.put(test1.get_ID(), test1); cache.put(test2.get_ID(), test2); cache.put(test3.get_ID(), test3); cache.clearResetCount(); commit(); getTrx().start(); try { Thread.sleep(500); } catch (InterruptedException e) { } assertTrue(cache.getResetCount() == 0, "Cache reset count is not zero with suspendTableCacheReset active"); //test delete and cache reset after suspend reset call cache.put(test1.get_ID(), test1); cache.put(test2.get_ID(), test2); cache.put(test3.get_ID(), test3); test1.deleteEx(true); test1 = null; test2.deleteEx(true); test2 = null; test3.deleteEx(true); test3 = null; cache.clearResetCount(); commit(); getTrx().start(); try { Thread.sleep(500); } catch (InterruptedException e) { } assertTrue(cache.getResetCount() == 0, "Cache reset count is not zero with suspendTableCacheReset active"); //test update and cache reset again after resume reset call CacheMgt.get().resumeTableCacheReset(MTest.Table_Name); test1 = new MTest(Env.getCtx(), 0, getTrxName()); test2 = new MTest(Env.getCtx(), 0, getTrxName()); test3 = new MTest(Env.getCtx(), 0, getTrxName()); test1.setName("test1"); test1.saveEx(); test2.setName("test2"); test2.saveEx(); test3.setName("test3"); test3.saveEx(); cache.put(test1.get_ID(), test1); cache.put(test2.get_ID(), test2); cache.put(test3.get_ID(), test3); cache.clearResetCount(); commit(); getTrx().start(); try { Thread.sleep(500); } catch (InterruptedException e) { } assertTrue(cache.getResetCount() > 0, "Cache reset count is zero"); } finally { if (test1 != null && test1.get_ID() > 0) test1.deleteEx(true); if (test2 != null && test2.get_ID() > 0) test2.deleteEx(true); if (test3 != null && test3.get_ID() > 0) test3.deleteEx(true); commit(); } } @Test public void testExpire() { ImmutableIntPOCache cache = new ImmutableIntPOCache(MProduct.Table_Name, 40, 1); //1 minutes cache.put(DictionaryIDs.M_Product.AZALEA_BUSH.id, new MProduct(Env.getCtx(), DictionaryIDs.M_Product.AZALEA_BUSH.id, null)); cache.put(DictionaryIDs.M_Product.P_CHAIR.id, new MProduct(Env.getCtx(), DictionaryIDs.M_Product.P_CHAIR.id, null)); for(int i = 0; i < 2; i++) { assertNotNull(cache.get(DictionaryIDs.M_Product.P_CHAIR.id), "Unexpected expire of cache item after " + i + " access"); try { Thread.sleep(35*1000); //35 seconds } catch (InterruptedException e) {} } assertNotNull(cache.get(DictionaryIDs.M_Product.P_CHAIR.id), "Cache item expire despite being access recently"); assertNull(cache.get(DictionaryIDs.M_Product.AZALEA_BUSH.id), "Cache item not expire despite not being access for more than 1 minutes"); CacheMgt.get().unregister(cache); } @Test public void testNullKey() { CCache testCache = new CCache(null, "Test_Cache", 10, 60, false); assertThatNoException().isThrownBy(() -> testCache.get(null)); assertThatNoException().isThrownBy(() -> testCache.containsKey(null)); assertThatNoException().isThrownBy(() -> testCache.containsValue(null)); assertFalse(testCache.containsValue(null)); testCache.put("TestNull", null); assertFalse(testCache.containsValue(null)); // still false because null is an unknown value } @Test public void testTrlCacheReset() { // test cache reset String locale = "es_CO"; MProduct p = new MProduct(Env.getCtx(), DictionaryIDs.M_Product.AZALEA_BUSH.id, null); String esName = p.get_Translation("Name", locale); Query query = new Query(Env.getCtx(), MProduct.Table_Name+"_Trl", "M_Product_ID=? AND AD_Language=?", null); PO po = query.setParameters(p.get_ID(), locale).firstOnly(); assertEquals(esName, po.get_Value("Name"), "Expected translation not found"); try { po.set_ValueOfColumn("Name", esName+"1"); po.saveEx(); try { Thread.sleep(500); } catch (InterruptedException e) { } assertEquals(esName+"1", p.get_Translation("Name", locale), "Translation not refresh in cache"); } finally { po.set_ValueOfColumn("Name", esName); po.saveEx(); } } }