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
   * <p>
   * http://www.apache.org/licenses/LICENSE-2.0
   * <p>
   * 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.atlas.repository.userprofile;
  
  import org.apache.atlas.AtlasErrorCode;
  import org.apache.atlas.TestModules;
  import org.apache.atlas.exception.AtlasBaseException;
  import org.apache.atlas.model.SearchFilter;
  import org.apache.atlas.model.discovery.SearchParameters;
  import org.apache.atlas.model.profile.AtlasUserProfile;
  import org.apache.atlas.model.profile.AtlasUserSavedSearch;
  import org.apache.atlas.model.typedef.AtlasEntityDef;
  import org.apache.atlas.model.typedef.AtlasTypesDef;
  import org.apache.atlas.repository.AtlasTestBase;
  import org.apache.atlas.repository.graph.AtlasGraphProvider;
  import org.apache.atlas.repository.util.FilterUtil;
  import org.apache.atlas.store.AtlasTypeDefStore;
  import org.apache.atlas.type.AtlasType;
  import org.apache.atlas.type.AtlasTypeRegistry;
  import org.testng.annotations.AfterClass;
  import org.testng.annotations.BeforeClass;
  import org.testng.annotations.Guice;
  import org.testng.annotations.Test;
  
  import javax.inject.Inject;
  
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Optional;
  
  import static org.apache.atlas.model.profile.AtlasUserSavedSearch.SavedSearchType.BASIC;
  import static org.apache.atlas.utils.TestLoadModelUtils.loadModelFromJson;
  import static org.testng.Assert.assertEquals;
  import static org.testng.Assert.assertFalse;
  import static org.testng.Assert.assertNotNull;
  import static org.testng.Assert.assertTrue;
  
  @Guice(modules = TestModules.TestOnlyModule.class)
  public class UserProfileServiceTest extends AtlasTestBase {
      private static final int NUM_USERS    = 2;
      private static final int NUM_SEARCHES = 4;
  
      private final UserProfileService userProfileService;
      private final AtlasTypeDefStore  typeDefStore;
  
      @Inject
      public UserProfileServiceTest(AtlasTypeRegistry typeRegistry, AtlasTypeDefStore typeDefStore, UserProfileService userProfileService) throws IOException, AtlasBaseException {
          this.typeDefStore       = typeDefStore;
          this.userProfileService = userProfileService;
  
          loadModelFromJson("0010-base_model.json", typeDefStore, typeRegistry);
      }
  
      @BeforeClass
      public void initialize() throws Exception {
          super.initialize();
      }
  
      @AfterClass
      public void clear() throws Exception {
          AtlasGraphProvider.cleanup();
  
          super.cleanup();
      }
  
      @Test
      public void filterInternalType() throws AtlasBaseException {
          SearchFilter searchFilter = new SearchFilter();
  
          FilterUtil.addParamsToHideInternalType(searchFilter);
  
          AtlasTypesDef filteredTypeDefs = typeDefStore.searchTypesDef(searchFilter);
  
          assertNotNull(filteredTypeDefs);
  
          Optional<AtlasEntityDef> anyInternal = filteredTypeDefs.getEntityDefs().stream().filter(e -> e.getSuperTypes().contains("__internal")).findAny();
  
          assertFalse(anyInternal.isPresent());
      }
  
      @Test(dependsOnMethods = "filterInternalType")
      public void createsNewProfile() throws AtlasBaseException {
          for (int i = 0; i < NUM_USERS; i++) {
              AtlasUserProfile expected = getAtlasUserProfile(i);
              AtlasUserProfile actual   = userProfileService.saveUserProfile(expected);
  
              assertNotNull(actual);
              assertEquals(expected.getName(), actual.getName());
              assertEquals(expected.getFullName(), actual.getFullName());
              assertNotNull(actual.getGuid());
          }
      }
  
      @Test(dependsOnMethods = "createsNewProfile")
      public void saveSearchesForUser() throws AtlasBaseException {
          String           userName         = getIndexBasedUserName(0);
          SearchParameters searchParameters = getActualSearchParameters();
  
          for (int i = 0; i < NUM_SEARCHES; i++) {
              userProfileService.addSavedSearch(getDefaultSavedSearch(userName, getIndexBasedQueryName(i), searchParameters));
          }
  
          for (int i = 0; i < NUM_SEARCHES; i++) {
              AtlasUserSavedSearch savedSearch = userProfileService.getSavedSearch(userName, getIndexBasedQueryName(i));
  
              assertEquals(savedSearch.getName(), getIndexBasedQueryName(i));
              assertEquals(savedSearch.getSearchParameters(), searchParameters);
          }
      }
  
      @Test(dependsOnMethods = "saveSearchesForUser", expectedExceptions = AtlasBaseException.class)
      public void attemptToAddExistingSearch() throws AtlasBaseException {
          String           userName                = getIndexBasedUserName(0);
          SearchParameters expectedSearchParameter = getActualSearchParameters();
  
          for (int j = 0; j < NUM_SEARCHES; j++) {
              String               queryName = getIndexBasedQueryName(j);
              AtlasUserSavedSearch expected  = getDefaultSavedSearch(userName, queryName, expectedSearchParameter);
              AtlasUserSavedSearch actual    = userProfileService.addSavedSearch(expected);
  
              assertNotNull(actual);
              assertNotNull(actual.getGuid());
              assertEquals(actual.getOwnerName(), expected.getOwnerName());
              assertEquals(actual.getName(), expected.getName());
              assertEquals(actual.getSearchType(), expected.getSearchType());
              assertEquals(actual.getSearchParameters(), expected.getSearchParameters());
          }
      }
  
      @Test(dependsOnMethods = "attemptToAddExistingSearch")
      public void verifySavedSearchesForUser() throws AtlasBaseException {
          String                     userName = getIndexBasedUserName(0);
          List<AtlasUserSavedSearch> searches = userProfileService.getSavedSearches(userName);
          List<String>               names    = getIndexBasedQueryNamesList();
  
          for (int i = 0; i < names.size(); i++) {
              assertTrue(names.contains(searches.get(i).getName()), searches.get(i).getName() + " failed!");
          }
      }
  
      @Test(dependsOnMethods = "verifySavedSearchesForUser")
      public void verifyQueryConversionFromJSON() throws AtlasBaseException {
          List<AtlasUserSavedSearch> list = userProfileService.getSavedSearches("first-0");
  
          for (int i = 0; i < NUM_SEARCHES; i++) {
              SearchParameters sp   = list.get(i).getSearchParameters();
              String           json = AtlasType.toJson(sp);
  
              assertEquals(AtlasType.toJson(getActualSearchParameters()).replace("\n", "").replace(" ", ""), json);
          }
      }
  
      @Test(dependsOnMethods = "verifyQueryConversionFromJSON")
      public void addAdditionalSearchesForUser() throws AtlasBaseException {
          SearchParameters expectedSearchParameter = getActualSearchParameters();
  
          for (int i = 0; i < NUM_USERS; i++) {
              String userName = getIndexBasedUserName(i);
  
              for (int j = 0; j < 6; j++) {
                  String               queryName = getIndexBasedQueryName(NUM_SEARCHES + j);
                  AtlasUserSavedSearch actual    = userProfileService.addSavedSearch(getDefaultSavedSearch(userName, queryName, expectedSearchParameter));
  
                  assertNotNull(actual);
  
                  AtlasUserSavedSearch savedSearch = userProfileService.getSavedSearch(userName, queryName);
  
                  assertNotNull(savedSearch);
                  assertEquals(savedSearch.getSearchParameters(), expectedSearchParameter);
              }
          }
      }
  
      @Test(dependsOnMethods = "addAdditionalSearchesForUser")
      public void updateSearch() throws AtlasBaseException {
          String               userName  = getIndexBasedUserName(0);
          String               queryName = getIndexBasedQueryName(0);
          AtlasUserSavedSearch expected  = userProfileService.getSavedSearch(userName, queryName);
  
          assertNotNull(expected);
  
          SearchParameters sp = expected.getSearchParameters();
  
          sp.setClassification("new-classification");
  
          AtlasUserSavedSearch actual = userProfileService.updateSavedSearch(expected);
  
          assertNotNull(actual);
          assertNotNull(actual.getSearchParameters());
          assertEquals(actual.getSearchParameters().getClassification(), expected.getSearchParameters().getClassification());
      }
  
      @Test(dependsOnMethods = "updateSearch")
      public void deleteUsingGuid() throws AtlasBaseException {
          String               userName  = getIndexBasedUserName(0);
          String               queryName = getIndexBasedQueryName(1);
          AtlasUserSavedSearch expected  = userProfileService.getSavedSearch(userName, queryName);
  
          assertNotNull(expected);
  
          userProfileService.deleteSavedSearch(expected.getGuid());
  
          try {
              userProfileService.getSavedSearch(userName, queryName);
          } catch (AtlasBaseException ex) {
              assertEquals(ex.getAtlasErrorCode().name(), AtlasErrorCode.INSTANCE_BY_UNIQUE_ATTRIBUTE_NOT_FOUND.name());
          }
      }
  
      @Test(dependsOnMethods = "deleteUsingGuid")
      public void deleteSavedQuery() throws AtlasBaseException {
          String           userName = getIndexBasedUserName(0);
          AtlasUserProfile expected = userProfileService.getUserProfile(userName);
  
          assertNotNull(expected);
  
          int    searchCount          = expected.getSavedSearches().size();
          String queryNameToBeDeleted = getIndexBasedQueryName(NUM_SEARCHES - 2);
  
          userProfileService.deleteSearchBySearchName(userName, queryNameToBeDeleted);
  
          List<AtlasUserSavedSearch> savedSearchList = userProfileService.getSavedSearches(userName);
  
          assertEquals(savedSearchList.size(), searchCount - 1);
      }
  
      @Test(dependsOnMethods = "deleteSavedQuery")
      void deleteUser() throws AtlasBaseException {
          String           userName    = getIndexBasedUserName(0);
          AtlasUserProfile userProfile = userProfileService.getUserProfile(userName);
  
          if (userProfile.getSavedSearches() != null) {
              for (AtlasUserSavedSearch savedSearch : userProfile.getSavedSearches()) {
                  userProfileService.deleteSavedSearch(savedSearch.getGuid());
              }
          }
  
          userProfileService.deleteUserProfile(userName);
  
          try {
              userProfileService.getUserProfile(userName);
          } catch (AtlasBaseException ex) {
              assertEquals(ex.getAtlasErrorCode().name(), AtlasErrorCode.INSTANCE_BY_UNIQUE_ATTRIBUTE_NOT_FOUND.name());
          }
      }
  
      private static AtlasUserProfile getAtlasUserProfile(Integer s) {
          return new AtlasUserProfile(getIndexBasedUserName(s), String.format("first-%s last-%s", s, s));
      }
  
      private static String getIndexBasedUserName(Integer i) {
          return String.format("first-%s", i.toString());
      }
  
      private static String getIndexBasedQueryName(Integer i) {
          return String.format("testQuery-%s", i.toString());
      }
  
      private SearchParameters getActualSearchParameters() {
          SearchParameters sp = new SearchParameters();
  
          sp.setClassification("test-classification");
          sp.setQuery("g.v().has('__guid').__guid.toList()");
          sp.setLimit(10);
          sp.setTypeName("some-type");
  
          return sp;
      }
  
      private AtlasUserSavedSearch getDefaultSavedSearch(String userName, String queryName, SearchParameters expectedSearchParam) {
          return new AtlasUserSavedSearch(userName, queryName, BASIC, expectedSearchParam);
      }
  
      private List<String> getIndexBasedQueryNamesList() {
          List<String> list = new ArrayList<>();
  
          for (int i = 0; i < NUM_SEARCHES; i++) {
              list.add(getIndexBasedQueryName(i));
          }
  
          return list;
      }
  }
  