static HoodieSyncTool instantiateMetaSyncTool(String syncToolClassName,
                                                TypedProperties props,
                                                Configuration hadoopConfig,
                                                FileSystem fs,
                                                String targetBasePath,
                                                String baseFileFormat) {
    TypedProperties properties = new TypedProperties();
    properties.putAll(props);
    properties.put(META_SYNC_BASE_PATH.key(), targetBasePath);
    properties.put(META_SYNC_BASE_FILE_FORMAT.key(), baseFileFormat);
    if (properties.containsKey(META_SYNC_TABLE_NAME.key())) {
      String tableName = properties.getString(META_SYNC_TABLE_NAME.key());
      if (!tableName.equals(tableName.toLowerCase())) {
        LOG.warn(
            "Table name \"" + tableName + "\" contains capital letters. Your metastore may automatically convert this to lower case and can cause table not found errors during subsequent syncs.");
      }
    }

    if (ReflectionUtils.hasConstructor(syncToolClassName,
        new Class<?>[] {Properties.class, Configuration.class})) {
      return ((HoodieSyncTool) ReflectionUtils.loadClass(syncToolClassName,
          new Class<?>[] {Properties.class, Configuration.class},
          properties, hadoopConfig));
    } else if (ReflectionUtils.hasConstructor(syncToolClassName,
        new Class<?>[] {Properties.class})) {
      return ((HoodieSyncTool) ReflectionUtils.loadClass(syncToolClassName,
          new Class<?>[] {Properties.class},
          properties));
    } else if (ReflectionUtils.hasConstructor(syncToolClassName,
        new Class<?>[] {TypedProperties.class, Configuration.class, FileSystem.class})) {
      return ((HoodieSyncTool) ReflectionUtils.loadClass(syncToolClassName,
          new Class<?>[] {TypedProperties.class, Configuration.class, FileSystem.class},
          properties, hadoopConfig, fs));
    } else if (ReflectionUtils.hasConstructor(syncToolClassName,
        new Class<?>[] {Properties.class, FileSystem.class})) {
      return ((HoodieSyncTool) ReflectionUtils.loadClass(syncToolClassName,
          new Class<?>[] {Properties.class, FileSystem.class},
          properties, fs));
    } else {
      throw new HoodieException("Could not load meta sync class " + syncToolClassName
          + ": no valid constructor found.");
    }
  }
@Test
  public void testCreateInvalidSyncClass() {
    Throwable t = assertThrows(HoodieException.class, () -> {
      SyncUtilHelpers.instantiateMetaSyncTool(
          InvalidSyncTool.class.getName(),
          new TypedProperties(),
          hadoopConf,
          fileSystem,
          BASE_PATH,
          BASE_FORMAT
      );
    });

    String expectedMessage = "Could not load meta sync class " + InvalidSyncTool.class.getName()
        + ": no valid constructor found.";
    assertEquals(expectedMessage, t.getMessage());
  }