void importPlaylistItems(
      List<MusicPlaylistItem> playlistItems,
      IdempotentImportExecutor executor,
      UUID jobId,
      TokensAndUrlAuthData authData)
      throws Exception {
    if (playlistItems != null && !playlistItems.isEmpty()) {
      Map<String, List<MusicPlaylistItem>> playlistItemsByPlaylist =
          playlistItems.stream()
              .filter(playlistItem -> !executor.isKeyCached(playlistItem.toString()))
              .collect(Collectors.groupingBy(MusicPlaylistItem::getPlaylistId));

      for (Entry<String, List<MusicPlaylistItem>> playlistEntry :
          playlistItemsByPlaylist.entrySet()) {
        String originalPlaylistId = playlistEntry.getKey();
        UnmodifiableIterator<List<MusicPlaylistItem>> batches =
            Iterators.partition(playlistEntry.getValue().iterator(), PLAYLIST_ITEM_BATCH_SIZE);
        while (batches.hasNext()) {
          importPlaylistItemBatch(jobId, authData, batches.next(), executor, originalPlaylistId);
        }
      }
    }

    return;
  }
@Test
  public void failOnePlaylistItem() throws Exception {
    importPlaylistSetUp("p1_id", "p1_title");
    importPlaylistSetUp("p2_id", "p2_title");

    MusicPlaylistItem playlistItem1 =
        new MusicPlaylistItem(
            new MusicRecording(
                "item1_isrc", null, 180000L, new MusicRelease("r1_icpn", null, null), null, false),
            "p1_id",
            1);
    MusicPlaylistItem playlistItem2 =
        new MusicPlaylistItem(
            new MusicRecording(
                "item1_isrc", null, 180000L, new MusicRelease("r1_icpn", null, null), null, false),
            "p2_id",
            1);
    GooglePlaylistItem googlePlaylistItem = buildGooglePlaylistItem("item1_isrc", "r1_icpn");
    BatchPlaylistItemRequest batchPlaylistItemRequest1 =
        new BatchPlaylistItemRequest(
            Lists.newArrayList(
                new ImportPlaylistItemRequest("p1_id", googlePlaylistItem)),
            "p1_id");
    BatchPlaylistItemRequest batchPlaylistItemRequest2 =
        new BatchPlaylistItemRequest(
            Lists.newArrayList(
                new ImportPlaylistItemRequest("p2_id", googlePlaylistItem)),
            "p2_id");
    BatchPlaylistItemResponse batchPlaylistItemResponse1 =
        new BatchPlaylistItemResponse(
            new NewPlaylistItemResult[]{
                buildPlaylistItemResult("item1_isrc", "r1_icpn", Code.OK_VALUE, null)
            });
    BatchPlaylistItemResponse batchPlaylistItemResponse2 =
        new BatchPlaylistItemResponse(
            new NewPlaylistItemResult[]{
                buildPlaylistItemResult("item1_isrc", "r1_icpn", Code.INVALID_ARGUMENT_VALUE, "")
            });
    when(googleMusicHttpApi.importPlaylistItems(eq(batchPlaylistItemRequest1)))
        .thenReturn(batchPlaylistItemResponse1);
    when(googleMusicHttpApi.importPlaylistItems(eq(batchPlaylistItemRequest2)))
        .thenReturn(batchPlaylistItemResponse2);

    // Run test
    googleMusicImporter.importPlaylistItems(
        Lists.newArrayList(playlistItem1, playlistItem2), executor, uuid, null);

    // One playlist item is imported
    assertTrue(executor.isKeyCached(String.valueOf(playlistItem1)));
    // Expected executor to have one error
    assertThat(executor.getErrors()).hasSize(1);
    ErrorDetail errorDetail = executor.getErrors().iterator().next();
    assertEquals(String.valueOf(playlistItem2), errorDetail.id());
    assertThat(errorDetail.exception()).contains("PlaylistItem could not be created.");
  }