content: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you 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.apache.cloudstack.storage.browser;
  
  import com.cloud.agent.api.Answer;
  import com.cloud.agent.api.UnsupportedAnswer;
  import com.cloud.api.query.dao.ImageStoreJoinDao;
  import com.cloud.api.query.vo.ImageStoreJoinVO;
  import com.cloud.storage.DataStoreRole;
  import com.cloud.storage.SnapshotVO;
  import com.cloud.storage.Storage;
  import com.cloud.storage.VMTemplateStoragePoolVO;
  import com.cloud.storage.VMTemplateVO;
  import com.cloud.storage.VolumeVO;
  import com.cloud.storage.dao.SnapshotDao;
  import com.cloud.storage.dao.VMTemplateDao;
  import com.cloud.storage.dao.VMTemplatePoolDao;
  import com.cloud.storage.dao.VolumeDao;
  import com.cloud.utils.exception.CloudRuntimeException;
  import org.apache.cloudstack.api.command.admin.storage.DownloadImageStoreObjectCmd;
  import org.apache.cloudstack.api.command.admin.storage.ListImageStoreObjectsCmd;
  import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolObjectsCmd;
  import org.apache.cloudstack.api.response.ListResponse;
  import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
  import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
  import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
  import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
  import org.apache.cloudstack.storage.command.browser.ListDataStoreObjectsAnswer;
  import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
  import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
  import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
  import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
  import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao;
  import org.junit.After;
  import org.junit.Assert;
  import org.junit.Before;
  import org.junit.Test;
  import org.mockito.InjectMocks;
  import org.mockito.Mock;
  import org.mockito.Mockito;
  import org.mockito.MockitoAnnotations;
  import org.mockito.Spy;
  
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  public class StorageBrowserImplTest {
  
      @Mock
      ImageStoreJoinDao imageStoreJoinDao;
  
      @Mock
      DataStoreManager dataStoreMgr;
  
      @Mock
      TemplateDataStoreDao templateDataStoreDao;
  
      @Mock
      SnapshotDataStoreDao snapshotDataStoreDao;
  
      @Mock
      SnapshotDao snapshotDao;
  
      @Mock
      EndPointSelector endPointSelector;
  
      @Mock
      VMTemplatePoolDao templatePoolDao;
  
      @Mock
      VMTemplateDao templateDao;
  
      @Mock
      VolumeDao volumeDao;
  
      @Mock
      VolumeDataStoreDao volumeDataStoreDao;
  
      @InjectMocks
      @Spy
      private StorageBrowserImpl storageBrowser;
  
      private AutoCloseable closeable;
  
      @Before
      public void setUp() throws Exception {
          closeable = MockitoAnnotations.openMocks(this);
      }
  
      @After
      public void tearDown() throws Exception {
          closeable.close();
      }
  
      @Test
      public void testGetPathVolumeMapForPrimaryDSNoVolumes() {
          List<String> paths = List.of("volume1", "volume2");
          Mockito.when(volumeDao.listByPoolIdAndPaths(1, paths)).thenReturn(null);
          Map<String, VolumeVO> result = storageBrowser.getPathVolumeMapForPrimaryDS(1L, paths);
          Assert.assertTrue(result.isEmpty());
      }
  
      @Test
      public void testGetPathVolumeMapForPrimaryDS() {
          List<String> paths = List.of("volume1", "volume2");
          VolumeVO volume = Mockito.mock(VolumeVO.class);
          Mockito.when(volume.getPath()).thenReturn("volume1");
  
          Mockito.when(volumeDao.listByPoolIdAndPaths(1, paths)).thenReturn(List.of(volume));
          Map<String, VolumeVO> result = storageBrowser.getPathVolumeMapForPrimaryDS(1L, paths);
          Assert.assertEquals(1, result.size());
          Assert.assertEquals(volume, result.get("volume1"));
      }
  
      @Test
      public void testGetPathTemplateMapForPrimaryDSNoTemplates() {
          List<String> paths = List.of("template1", "template2");
          Mockito.when(templatePoolDao.listByPoolIdAndInstallPath(1L, paths)).thenReturn(null);
          Map<String, VMTemplateVO> result = storageBrowser.getPathTemplateMapForPrimaryDS(1L, paths);
          Assert.assertTrue(result.isEmpty());
      }
  
      @Test
      public void testGetPathTemplateMapForPrimaryDS() {
          List<String> paths = List.of("template1", "template2");
          VMTemplateStoragePoolVO templatePool = Mockito.mock(VMTemplateStoragePoolVO.class);
          Mockito.when(templatePool.getTemplateId()).thenReturn(5L);
          Mockito.when(templatePool.getInstallPath()).thenReturn("template1");
  
          VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
          Mockito.when(template.getId()).thenReturn(5L);
  
          Mockito.when(templateDao.listByIds(List.of(5L))).thenReturn(List.of(template));
  
          List<VMTemplateStoragePoolVO> templateStoragePoolList = List.of(templatePool);
          Mockito.when(templatePoolDao.listByPoolIdAndInstallPath(1L, paths)).thenReturn(templateStoragePoolList);
          Map<String, VMTemplateVO> result = storageBrowser.getPathTemplateMapForPrimaryDS(1L, paths);
          Assert.assertEquals(1L, result.size());
          Assert.assertEquals(template, result.get("template1"));
      }
  
      @Test
      public void testGetFormattedPaths() {
          List<String> paths = List.of("/path/to/file", "/path/to/file/", "path/to/file", "path/to/file/");
          List<String> expectedFormattedPaths = List.of("path/to/file", "path/to/file", "path/to/file", "path/to/file");
  
          List<String> formattedPaths = storageBrowser.getFormattedPaths(paths);
  
          Assert.assertEquals(expectedFormattedPaths, formattedPaths);
      }
  
      @Test
      public void testListImageStore() {
          ListImageStoreObjectsCmd cmd = Mockito.mock(ListImageStoreObjectsCmd.class);
          Long imageStoreId = 1L;
          String path = "path/to/image/store";
          Mockito.when(cmd.getStoreId()).thenReturn(imageStoreId);
          Mockito.when(cmd.getPath()).thenReturn(path);
          Mockito.when(cmd.getStartIndex()).thenReturn(0L);
          Mockito.when(cmd.getPageSizeVal()).thenReturn(10L);
  
          ImageStoreJoinVO imageStore = Mockito.mock(ImageStoreJoinVO.class);
          Mockito.when(imageStoreJoinDao.findById(imageStoreId)).thenReturn(imageStore);
  
          DataStore dataStore = Mockito.mock(DataStore.class);
          Mockito.when(dataStoreMgr.getDataStore(imageStoreId, imageStore.getRole())).thenReturn(dataStore);
  
          ListDataStoreObjectsAnswer answer = Mockito.mock(ListDataStoreObjectsAnswer.class);
          Mockito.doReturn(answer).when(storageBrowser).listObjectsInStore(dataStore, path, 0, 10);
  
          ListResponse<DataStoreObjectResponse> response = storageBrowser.listImageStoreObjects(cmd);
  
          Assert.assertNotNull(response);
      }
  
      @Test
      public void testListPrimaryStore() {
          ListStoragePoolObjectsCmd cmd = Mockito.mock(ListStoragePoolObjectsCmd.class);
          Long storeId = 1L;
          String path = "path/to/primary/store";
          Mockito.when(cmd.getStoreId()).thenReturn(storeId);
          Mockito.when(cmd.getPath()).thenReturn(path);
          Mockito.when(cmd.getStartIndex()).thenReturn(0L);
          Mockito.when(cmd.getPageSizeVal()).thenReturn(10L);
  
          DataStore dataStore = Mockito.mock(DataStore.class);
          Mockito.when(dataStoreMgr.getDataStore(storeId, DataStoreRole.Primary)).thenReturn(dataStore);
  
          ListDataStoreObjectsAnswer answer = Mockito.mock(ListDataStoreObjectsAnswer.class);
          Mockito.doReturn(answer).when(storageBrowser).listObjectsInStore(dataStore, path, 0, 10);
  
          ListResponse<DataStoreObjectResponse> response = storageBrowser.listPrimaryStoreObjects(cmd);
  
          Assert.assertNotNull(response);
          Assert.assertEquals(answer.getPaths().size(), response.getResponses().size());
      }
  
      @Test
      public void testGetCommands() {
          List<Class<?>> expectedCmdList = new ArrayList<>();
          expectedCmdList.add(ListImageStoreObjectsCmd.class);
          expectedCmdList.add(ListStoragePoolObjectsCmd.class);
          expectedCmdList.add(DownloadImageStoreObjectCmd.class);
  
          List<Class<?>> cmdList = storageBrowser.getCommands();
  
          Assert.assertNotNull(cmdList);
          Assert.assertEquals(expectedCmdList, cmdList);
      }
  
      @Test
      public void testListObjectsInStoreNoEndpoint() {
          DataStore dataStore = Mockito.mock(DataStore.class);
          String path = "path/to/store";
          int startIndex = 0;
          int pageSize = 10;
  
          Mockito.when(endPointSelector.select(dataStore)).thenReturn(null);
  
          try {
              storageBrowser.listObjectsInStore(dataStore, path, startIndex, pageSize);
          } catch (CloudRuntimeException exception) {
              Assert.assertEquals("No remote endpoint to send command", exception.getMessage());
          }
      }
  
      @Test
      public void testListObjectsInStoreBadCommand() {
          DataStore dataStore = Mockito.mock(DataStore.class);
          String path = "path/to/store";
          int startIndex = 0;
          int pageSize = 10;
  
          EndPoint ep = Mockito.mock(EndPoint.class);
  
          Mockito.when(endPointSelector.select(dataStore)).thenReturn(ep);
          Answer answer = Mockito.mock(UnsupportedAnswer.class);
          Mockito.when(ep.sendMessage(Mockito.any())).thenReturn(answer);
  
          try {
              storageBrowser.listObjectsInStore(dataStore, path, startIndex, pageSize);
          } catch (CloudRuntimeException exception) {
              Assert.assertEquals("Failed to list datastore objects", exception.getMessage());
          }
      }
  
      @Test
      public void testListObjectsInStorePathDoesNotExist() {
          DataStore dataStore = Mockito.mock(DataStore.class);
          String path = "path/to/store";
          int startIndex = 0;
          int pageSize = 10;
  
          EndPoint ep = Mockito.mock(EndPoint.class);
  
          Mockito.when(endPointSelector.select(dataStore)).thenReturn(ep);
          ListDataStoreObjectsAnswer answer = Mockito.mock(ListDataStoreObjectsAnswer.class);
          Mockito.when(ep.sendMessage(Mockito.any())).thenReturn(answer);
          Mockito.when(answer.getResult()).thenReturn(true);
          Mockito.when(answer.isPathExists()).thenReturn(false);
          Mockito.when(dataStore.getUuid()).thenReturn("uuid");
  
          try {
              storageBrowser.listObjectsInStore(dataStore, path, startIndex, pageSize);
          } catch (IllegalArgumentException exception) {
              Assert.assertEquals("Path " + path + " doesn't exist in store: " + dataStore.getUuid(), exception.getMessage());
          }
      }
  
      @Test
      public void testListObjectsInStore() {
          DataStore dataStore = Mockito.mock(DataStore.class);
          String path = "path/to/store";
          int startIndex = 0;
          int pageSize = 10;
  
          EndPoint ep = Mockito.mock(EndPoint.class);
  
          Mockito.when(endPointSelector.select(dataStore)).thenReturn(ep);
          ListDataStoreObjectsAnswer answer = Mockito.mock(ListDataStoreObjectsAnswer.class);
          Mockito.when(ep.sendMessage(Mockito.any())).thenReturn(answer);
          Mockito.when(answer.getResult()).thenReturn(true);
          Mockito.when(answer.isPathExists()).thenReturn(true);
  
          Assert.assertEquals(answer, storageBrowser.listObjectsInStore(dataStore, path, startIndex, pageSize));
      }
  
      @Test
      public void testGetPathTemplateMapForSecondaryDS() {
          long dataStoreId = 1L;
          List<String> paths = List.of("/path1", "/path2");
  
          TemplateDataStoreVO templateDataStore1 = Mockito.mock(TemplateDataStoreVO.class);
          Mockito.when(templateDataStore1.getInstallPath()).thenReturn("/path1");
          Mockito.when(templateDataStore1.getTemplateId()).thenReturn(1L);
  
          TemplateDataStoreVO templateDataStore2 = Mockito.mock(TemplateDataStoreVO.class);
          Mockito.when(templateDataStore2.getInstallPath()).thenReturn("/path2");
          Mockito.when(templateDataStore2.getTemplateId()).thenReturn(2L);
  
          List<TemplateDataStoreVO> templateList = List.of(templateDataStore1, templateDataStore2);
  
          VMTemplateVO template1 = Mockito.mock(VMTemplateVO.class);
          Mockito.when(template1.getId()).thenReturn(1L);
  
          VMTemplateVO template2 = Mockito.mock(VMTemplateVO.class);
          Mockito.when(template2.getId()).thenReturn(2L);
  
          List<VMTemplateVO> templates = List.of(template1, template2);
  
          Mockito.when(templateDataStoreDao.listByStoreIdAndInstallPaths(dataStoreId, paths)).thenReturn(templateList);
          Mockito.when(templateDao.listByIds(List.of(1L, 2L))).thenReturn(templates);
  
          Map<String, VMTemplateVO> expectedPathTemplateMap = new HashMap<>();
          expectedPathTemplateMap.put("/path1", template1);
          expectedPathTemplateMap.put("/path2", template2);
  
          Map<String, VMTemplateVO> actualPathTemplateMap = storageBrowser.getPathTemplateMapForSecondaryDS(dataStoreId, paths);
  
          Assert.assertEquals(expectedPathTemplateMap, actualPathTemplateMap);
      }
  
      @Test
      public void testGetPathSnapshotMapForSecondaryDS() {
          long dataStoreId = 1L;
          List<String> paths = List.of("/path1", "/path2");
  
          SnapshotDataStoreVO snapshotDataStore1 = Mockito.mock(SnapshotDataStoreVO.class);
          Mockito.when(snapshotDataStore1.getInstallPath()).thenReturn("/path1");
          Mockito.when(snapshotDataStore1.getSnapshotId()).thenReturn(1L);
  
          SnapshotDataStoreVO snapshotDataStore2 = Mockito.mock(SnapshotDataStoreVO.class);
          Mockito.when(snapshotDataStore2.getInstallPath()).thenReturn("/path2");
          Mockito.when(snapshotDataStore2.getSnapshotId()).thenReturn(2L);
  
          List<SnapshotDataStoreVO> snapshotDataStoreList = List.of(snapshotDataStore1, snapshotDataStore2);
  
          SnapshotVO snapshot1 = Mockito.mock(SnapshotVO.class);
          Mockito.when(snapshot1.getId()).thenReturn(1L);
  
          SnapshotVO snapshot2 = Mockito.mock(SnapshotVO.class);
          Mockito.when(snapshot2.getId()).thenReturn(2L);
  
          List<SnapshotVO> snapshots = List.of(snapshot1, snapshot2);
  
          Mockito.when(snapshotDataStoreDao.listByStoreAndInstallPaths(dataStoreId, DataStoreRole.Image, paths)).thenReturn(snapshotDataStoreList);
          Mockito.when(snapshotDao.listByIds(new Long[]{1L, 2L})).thenReturn(snapshots);
  
          Map<String, SnapshotVO> expectedSnapshotPathMap = new HashMap<>();
          expectedSnapshotPathMap.put("/path1", snapshot1);
          expectedSnapshotPathMap.put("/path2", snapshot2);
  
          Map<String, SnapshotVO> snapshotPathMap = storageBrowser.getPathSnapshotMapForSecondaryDS(dataStoreId, paths);
  
          Assert.assertEquals(expectedSnapshotPathMap, snapshotPathMap);
      }
  
      @Test
      public void testGetPathSnapshotMapForPrimaryDS() {
          long dataStoreId = 1L;
          List<String> paths = List.of("path1", "path2");
          List<String> absPaths = List.of("/mnt/path1", "/mnt/path2");
  
          SnapshotDataStoreVO snapshotDataStore1 = Mockito.mock(SnapshotDataStoreVO.class);
          Mockito.when(snapshotDataStore1.getInstallPath()).thenReturn("/mnt/path1");
          Mockito.when(snapshotDataStore1.getSnapshotId()).thenReturn(1L);
  
          SnapshotDataStoreVO snapshotDataStore2 = Mockito.mock(SnapshotDataStoreVO.class);
          Mockito.when(snapshotDataStore2.getInstallPath()).thenReturn("/mnt/path2");
          Mockito.when(snapshotDataStore2.getSnapshotId()).thenReturn(2L);
  
          List<SnapshotDataStoreVO> snapshotDataStoreList = List.of(snapshotDataStore1, snapshotDataStore2);
  
          SnapshotVO snapshot1 = Mockito.mock(SnapshotVO.class);
          Mockito.when(snapshot1.getId()).thenReturn(1L);
  
          SnapshotVO snapshot2 = Mockito.mock(SnapshotVO.class);
          Mockito.when(snapshot2.getId()).thenReturn(2L);
  
          List<SnapshotVO> snapshots = List.of(snapshot1, snapshot2);
  
          Mockito.when(snapshotDataStoreDao.listByStoreAndInstallPaths(dataStoreId, DataStoreRole.Primary, absPaths)).thenReturn(snapshotDataStoreList);
          Mockito.when(snapshotDao.listByIds(new Long[]{1L, 2L})).thenReturn(snapshots);
  
          Map<String, SnapshotVO> expectedSnapshotPathMap = new HashMap<>();
          expectedSnapshotPathMap.put("path1", snapshot1);
          expectedSnapshotPathMap.put("path2", snapshot2);
  
          Map<String, SnapshotVO> snapshotPathMap = storageBrowser.getPathSnapshotMapForPrimaryDS(dataStoreId, paths, absPaths);
  
          Assert.assertEquals(expectedSnapshotPathMap, snapshotPathMap);
      }
  
      @Test
      public void testGetResponse() {
          ListDataStoreObjectsAnswer answer = Mockito.mock(ListDataStoreObjectsAnswer.class);
          Mockito.when(answer.getPaths()).thenReturn(List.of("/path1", "/path2"));
          Mockito.when(answer.getAbsPaths()).thenReturn(List.of("/path1", "/path2"));
          Mockito.when(answer.getNames()).thenReturn(List.of("name1", "name2"));
          Mockito.when(answer.getIsDirs()).thenReturn(List.of(true, false));
          Mockito.when(answer.getSizes()).thenReturn(List.of(100L, 200L));
          Mockito.when(answer.getLastModified()).thenReturn(List.of((new Date()).getTime(), (new Date()).getTime()));
  
          List<String> paths = List.of("path1", "path2");
          List<String> absPaths = List.of("/path1", "/path2");
  
          Map<String, SnapshotVO> pathSnapshotMap = new HashMap<>();
          pathSnapshotMap.put("path1", Mockito.mock(SnapshotVO.class));
  
          VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
          Map<String, VMTemplateVO> pathTemplateMap = new HashMap<>();
          pathTemplateMap.put("path2", template);
          Mockito.when(template.getFormat()).thenReturn(Storage.ImageFormat.ISO);
  
          Map<String, VolumeVO> pathVolumeMap = new HashMap<>();
          pathVolumeMap.put("path1", Mockito.mock(VolumeVO.class));
  
          DataStore dataStore = Mockito.mock(DataStore.class);
  
          Mockito.when(dataStore.getRole()).thenReturn(DataStoreRole.Primary);
          Mockito.when(dataStore.getId()).thenReturn(1L);
          Mockito.doReturn(pathTemplateMap).when(storageBrowser).getPathTemplateMapForPrimaryDS(1L, paths);
          Mockito.doReturn(pathSnapshotMap).when(storageBrowser).getPathSnapshotMapForPrimaryDS(1L, paths, absPaths);
          Mockito.doReturn(pathVolumeMap).when(storageBrowser).getPathVolumeMapForPrimaryDS(1L, paths);
  
          ListResponse<DataStoreObjectResponse> response = storageBrowser.getResponse(dataStore, answer);
  
          Assert.assertEquals(2, response.getResponses().size());
          Assert.assertEquals("name1", response.getResponses().get(0).getName());
          Assert.assertEquals(true, response.getResponses().get(0).isDirectory());
          Assert.assertEquals(100L, response.getResponses().get(0).getSize());
          Assert.assertNotNull(response.getResponses().get(0).getLastUpdated());
  
          Assert.assertEquals("name2", response.getResponses().get(1).getName());
          Assert.assertEquals(false, response.getResponses().get(1).isDirectory());
          Assert.assertEquals(200L, response.getResponses().get(1).getSize());
          Assert.assertNotNull(response.getResponses().get(1).getLastUpdated());
      }
  }
  