All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alpine.plugin.test.mock.OperatorDialogMock.scala Maven / Gradle / Ivy

There is a newer version: 1.6-beta-2
Show newest version
package com.alpine.plugin.test.mock

import com.alpine.plugin.core.datasource.OperatorDataSourceManager
import com.alpine.plugin.core.dialog._
import com.alpine.plugin.core.io.ColumnType.TypeValue
import com.alpine.plugin.core.io._
import com.alpine.plugin.test.utils.OperatorParameterMockUtil

import scala.collection.JavaConversions._
import scala.util.{Success, Try}

abstract class DefaultDialogElementMock(val getId: String,
  val getLabel: String,
  val isRequired: Boolean = true) extends DialogElement {}

abstract class SingleElementSelectorMock(availableValues: Seq[String],
  val getSelectedValue: String,
  val getId: String,
  val getLabel: String,
  val isRequired: Boolean = true) extends SingleItemSelector {

  assert(availableValues.distinct.length.equals(availableValues.length),
    "The available values for the parameters " + getLabel + "are not distinct")
  assert(availableValues.contains(getSelectedValue), "The value " + getSelectedValue +
    " is not one of the available values for the parameter " + getLabel)
}

abstract class AbstractCheckboxMock(availableValues: Seq[String],
  selected: Seq[String],
  val getId: String,
  val getLabel: String,
  val isRequired: Boolean = true) extends Checkboxes {

  //validation logic
  selected.foreach(v =>
    assert(availableValues.contains(v), "The value " + v +
      " is not one of the available values for the parameter " + getLabel))
  assert(availableValues.distinct.length == availableValues.length,
    "The available values for the parameters " + getLabel + "are not distinct")
}

class OperatorDialogMock(overrideParams: OperatorParametersMock,
  input: IOBase) extends OperatorDialog {

  private val dialogElements = scala.collection.mutable.Map[String, DialogElement]()
  private val selectionGroupIdMap = scala.collection.mutable.Map[String, Set[String]]()

  val schemas: Seq[(String, TabularSchema)] = getSchemas(input)

  private val operatorParametersMock = new OperatorParametersMock(
    overrideParams.operatorInfo().name,
    overrideParams.operatorInfo().uuid
  )

  private val uuids: Seq[String] = {
    input match {
      case i: IOList[IOBase] => i.sources.map(_.uuid)
      case _ => Seq[String]()
    }
  }

  private def getSchemas(input: IOBase): Seq[(String, TabularSchema)] = {
    input match {
        //This doesn't actually address  the case of nested lists, since in that case we are perhaps
      // overriding the UUId of the nested list with the "parent" list operator UUID however it
      // will handle the case when we have a list of object  that do not have tabular schemas
      case i: IOList[IOBase] => i.sources.zip(i.elements).flatMap{ case (o, e) => getSchemas(e).map(x => (o.uuid, x._2)) }
      case t: com.alpine.plugin.core.io.Tuple => t.elements.flatMap(getSchemas(_))
      case table: TabularDataset => Seq(("", table.tabularSchema))
      case _ => Seq[(String, TabularSchema)]()
    }
  }

  def getTypeMapForColumnSelector(parentBoxID: Option[String],
    id: String): Map[String, TypeValue] = {

    assert(schemas.nonEmpty, "Cannot create tabular dataset column dropdown " + id + " for " +
      "non tabular input")

    val tabularSchema = if (parentBoxID.nonEmpty) {
      val de = dialogElements.get(parentBoxID.get)
      assert(de.isDefined && de.get.isInstanceOf[ParentOperatorDropdownBox],
        "Column selector " + id + " " +
          "contains parent id " + parentBoxID + "" +
          " but no parent box with this id has been added to this operator dialog.")
      val selectedValue = de.get.asInstanceOf[SingleElementSelectorMock].getSelectedValue
      schemas.filter(selectedValue == _._1).head._2

    } else {
      schemas.head._2
    }

    val nameTypeMap: Map[String, TypeValue] = tabularSchema.getDefinedColumns.map(x =>
      (x.columnName, x.columnType)).toMap
    nameTypeMap
  }

  private def updateDialogElements[T <: DialogElement](id: String, de: T): T = {
    assert(!dialogElements.contains(id), " You have already added a dialog element with key " + id)
    dialogElements.update(id, de)
    de
  }

  private def setStringValue(id: String, defaultSelection: String): String = {
    val selection = Try(overrideParams.getStringValue(id)) match {
      case Success(s) => s
      case _ => defaultSelection
    }

    operatorParametersMock.setValue(id, selection)
    selection
  }

  private def validateColumnSelectionAndUpdateSelectionGroup(column: String,
    selectionGroupId: String, filter: ColumnFilter, nameTypeMap: Map[String, TypeValue]): String = {

    val inputColumns = nameTypeMap.keySet

    assert(inputColumns.contains(column), "Column: " + column + " is not present in input schema.")

    val group = selectionGroupIdMap.getOrElseUpdate(selectionGroupId, Set())
    assert(!group.contains(column), "The selection group id: " + selectionGroupId +
      " already contains the column " + column)
    assert(column.matches(filter.acceptedNameRegex))
    val t = nameTypeMap(column)
    assert(filter.accepts(ColumnDef(column, t)), "The column, " + column + " has type " + t.name +
      " which is not one of the accepted type for the column filter which accepts: ")
    selectionGroupIdMap.update(selectionGroupId, group.union(Set(column)))
    column
  }

  /**
    * Returns a new mock parameters object with all the parameters that were added to this dialog object.
    */
  def getNewParameters: OperatorParametersMock = operatorParametersMock

  override def getLabel: String = "Label"

  def addStringBox(setup: StringDialogElementSetup): StringBox = {
    val selected = setStringValue(setup.id, setup.defaultValue.get)

    class StringBoxImpl extends DefaultDialogElementMock(setup.id, setup.label, setup.isRequired) with StringBox {
      assert(selected.matches(setup.regex.get), "The string: " + selected + "does not conform to regex: " + setup.regex.get)
    }

    val de = new StringBoxImpl()
    updateDialogElements(setup.id, de)
  }

  override def addStringBox(id: String, label: String, defaultValue: String, regex: String, width: Int, height: Int): StringBox = {
    addStringBox(new StringDialogElementSetup(id, label, isRequired = true, Option.apply(defaultValue), Option.apply(regex),
      isLarge = false, isPassword = false))
  }

  override def addStringBox(id: String, label: String, defaultValue: String, regex: String, required: Boolean): StringBox = {
    addStringBox(new StringDialogElementSetup(id, label, required, Option.apply(defaultValue), Option.apply(regex),
      isLarge = false, isPassword = false))
  }

  override def addLargeStringBox(id: String, label: String, defaultValue: String, regex: String, required: Boolean): StringBox = {
    addStringBox(new StringDialogElementSetup(id, label, required, Option.apply(defaultValue), Option.apply(regex),
      isLarge = true, isPassword = false))
  }

  override def addPasswordBox(id: String, label: String, regex: String, required: Boolean): StringBox = {
    addStringBox(new StringDialogElementSetup(id, label, required, Option.apply(""), Option.apply(regex),
      isLarge = false, isPassword = true))
  }

  override def getDialogElement(id: String): DialogElement = dialogElements(id)

  override def getDialogElements: Seq[DialogElement] = dialogElements.values.toSeq

  override def addDialogElement(des: DialogElementSetup): DialogElement = {
    des match {
      case n: NumericDialogElementSetup => {
        addDoubleBox(n)
      }
      case i: IntegerDialogElementSetup => {
        addIntegerBox(i)
      }
      case c: ChorusFileSelectorSetup => {
        addChorusFileDropdownBox(c)
      }
      case s: StringDialogElementSetup => {
        addStringBox(s)
      }
      case s: ScriptEditPopupSetup => {
        addScriptEditPopup(s)
      }
      case p: ParentOperatorSelectorSetup => {
        addParentOperatorDropdownBox(p)
      }
      case t: TabularDatasetColumnDropdownSetup => {
        addTabularDatasetColumnDropdownBox(t)
      }
      case d: DropdownBoxSetup => {
        addDropdownBox(d)
      }
      case r: RadioButtonSetup => {
        addRadioButtons(r)
      }
      case r: RowDialogSetup => {
        addRowDialog(r)
      }
    }
  }

  override def addCheckboxes(id: String, label: String, values: Seq[String], defaultSelections: Seq[String], required: Boolean): Checkboxes = {
    val selections: Seq[String] = Try(overrideParams.getStringArrayValue(id)) match {
      case Success(s) => s
      case _ => defaultSelections
    }

    OperatorParameterMockUtil.addCheckBoxSelections(operatorParametersMock, id, selections: _ *)

    class CheckBoxImpl extends AbstractCheckboxMock(values,
      selections, id, label, required) {}

    val de = new CheckBoxImpl
    updateDialogElements(id, de)
  }

  override def addCheckboxesFromJavaList(id: String, label: String, values: java.util.List[String], defaultSelections: java.util.List[String], required: Boolean): Checkboxes = {
    addCheckboxesFromJavaList(id, label, asScalaBuffer(values).toList, asScalaBuffer(defaultSelections).toList, required)
  }

  def addDropdownBox(setup: DropdownBoxSetup): DropdownBox = {
    val s = setStringValue(setup.id, setup.defaultSelection.get)
    class DropDownBoxImpl extends SingleElementSelectorMock(setup.values.get, s, setup.id, setup.label) with
      DropdownBox {
    }
    //toDo: ditch this sequence, do validation at object creation --> less mutable
    val de = new DropDownBoxImpl
    updateDialogElements(setup.id, de)
  }

  override def addDropdownBox(id: String, label: String, values: Seq[String], defaultSelection: String): DropdownBox = {
    addDropdownBox(new DropdownBoxSetup(id, label, isRequired = true, Option.apply(values), Option.apply(defaultSelection)))
  }

  override def addDropdownBoxFromJavaList(id: String, label: String, values: java.util.List[String], defaultSelection: String): DropdownBox = {
    addDropdownBox(new DropdownBoxSetup(id, label, isRequired = true, Option.apply(asScalaBuffer(values).toList), Option.apply(defaultSelection)))
  }

  override def addHdfsDirectorySelector(id: String, label: String, defaultPath: String): HdfsFileSelector = {
    addHdfsDirectorySelector(id, label, defaultPath, required = true)
  }

  override def addHdfsDirectorySelector(id: String, label: String, defaultPath: String, required: Boolean): HdfsFileSelector = {
    setStringValue(id, defaultPath)

    class HdfsFileSelectorImp extends DefaultDialogElementMock(id, label, required) with HdfsFileSelector

    val de = new HdfsFileSelectorImp
    updateDialogElements(id, de)
  }


  override def addOutputDirectorySelector(id: String, label: String, required: Boolean): HdfsFileSelector = {
    //TODO: Genericize this so that the "tds" part is not hard-coded?
    setStringValue(id, "@default_tempdir/tds_out/@user_name/@flow_name")
    class HdfsFileSelectorImp extends DefaultDialogElementMock(id, label, required) with HdfsFileSelector
    val de = new HdfsFileSelectorImp
    updateDialogElements(id, de)
  }

  override def addDataSourceDropdownBox(id: String, label: String,
    dataSourceManager: OperatorDataSourceManager): DataSourceDropdownBox = {
    setStringValue(id, dataSourceManager.getRuntimeDataSource.getName)
    val allSources = dataSourceManager.getAvailableDataSources.map(_.getName)
    class DataSourceDropdownBoxImpl extends DefaultDialogElementMock(id, label, true) with DataSourceDropdownBox

    val de = new DataSourceDropdownBoxImpl
    updateDialogElements(id, de)
  }


  override def addTabularDatasetColumnDropdownBox(id: String,
                                                  label: String,
                                                  columnFilter: ColumnFilter,
                                                  selectionGroupId: String,
                                                  required: Boolean): TabularDatasetColumnDropdownBox = {
    addTabularDatasetColumnDropdownBox(new TabularDatasetColumnDropdownSetup(id, label, required, columnFilter,
      selectionGroupId, None))
  }


  override def addTabularDatasetColumnDropdownBox(id: String,
                                                  label: String,
                                                  columnFilter: ColumnFilter,
                                                  selectionGroupId: String,
                                                  required: Boolean,
                                                  parentBoxID: Option[String]): TabularDatasetColumnDropdownBox = {
    addTabularDatasetColumnDropdownBox(new TabularDatasetColumnDropdownSetup(id, label, required, columnFilter,
      selectionGroupId, parentBoxID))
  }

  def addTabularDatasetColumnDropdownBox(setup: TabularDatasetColumnDropdownSetup) = {
    val columnTypeMap = getTypeMapForColumnSelector(setup.parentBoxId, setup.id)

    val selection: String = Try(overrideParams.getTabularDatasetSelectedColumn(setup.id)) match {
      case Success(s) =>
        val column = s._2
        validateColumnSelectionAndUpdateSelectionGroup(column, setup.selectionGroupId, setup.columnFilter, columnTypeMap)
      case _ => ""
    }

    assert(!(setup.isRequired && selection.equals("")))

    OperatorParameterMockUtil.addTabularColumn(operatorParametersMock, setup.id, selection)


    class TabularDatasetColumnDropdownBoxImpl extends
      SingleElementSelectorMock(
        columnTypeMap.keys.toSeq, selection, setup.id, setup.label, isRequired = setup.isRequired)
      with TabularDatasetColumnDropdownBox {

      assert(columnTypeMap.keySet.contains(selection),
        "The input of this operator does not contain the column " + selection +
          "in the input schema.")
    }

    val de = new TabularDatasetColumnDropdownBoxImpl
    updateDialogElements(setup.id, de)
  }

  override def addDBSchemaDropdownBox(id: String, label: String, defaultSchema: String): DBSchemaDropdownBox = {
    val selected = setStringValue(id, defaultSchema)
    class DBSchemaDropdownBoxImpl extends SingleElementSelectorMock(Seq(selected), selected, id, label)
      with DBSchemaDropdownBox {}

    val de = new DBSchemaDropdownBoxImpl
    updateDialogElements(id, de)

  }

  def addRadioButtons(setup: RadioButtonSetup): RadioButtons = {
    val selected = setStringValue(setup.id, setup.defaultSelection)

    class RadioButtonImpl extends SingleElementSelectorMock(setup.values, selected, setup.id, setup.label) with RadioButtons

    val de = new RadioButtonImpl
    updateDialogElements(setup.id, de)
  }

  override def addRadioButtons(id: String, label: String, values: Seq[String], defaultSelection: String): RadioButtons = {
    addRadioButtons(new RadioButtonSetup(id, label, isRequired = true, values, defaultSelection))
  }

  override def addRadioButtonsFromJavaList(id: String, label: String, values: java.util.List[String], defaultSelection: String): RadioButtons = {
    addRadioButtons(new RadioButtonSetup(id, label, isRequired = true, asScalaBuffer(values).toList, defaultSelection))
  }

  def addIntegerBox(setup: IntegerDialogElementSetup): IntegerBox = {
    val selection = Try(overrideParams.getIntValue(setup.id)) match {
      case Success(s) => s
      case _ => setup.defaultValue.get.toInt
    }
    require(selection >= setup.min.get.value || selection <= setup.max.get.value, "Selection:" + selection + " is not in range for integer parameter " + setup.label)
    operatorParametersMock.setValue(setup.id, selection)

    class IntegerBoxImpl extends DefaultDialogElementMock(setup.id, setup.label) with IntegerBox

    val de = new IntegerBoxImpl
    updateDialogElements(setup.id, de)
  }

  override def addIntegerBox(id: String, label: String, min: Int, max: Int, defaultValue: Int): IntegerBox = {
    addIntegerBox(new IntegerDialogElementSetup(id,label, isRequired = true, Option.apply(new NumericBound(min, inclusive = true)),
      Option.apply(new NumericBound(max, inclusive = true)), Option.apply(defaultValue.toString)))
  }

  override def addHdfsFileSelector(id: String, label: String, defaultPath: String): HdfsFileSelector = {
    addHdfsFileSelector(id, label, defaultPath, required = true)
  }

  override def addHdfsFileSelector(id: String, label: String, defaultPath: String, required: Boolean): HdfsFileSelector = {
    val selection = setStringValue(id, defaultPath)

    class HdfsFileSelectorImpl extends DefaultDialogElementMock(id, label, required) with HdfsFileSelector
    val de = new HdfsFileSelectorImpl
    updateDialogElements(id, de)
  }

  //toDo: Refactor to use column checkboxes
  override def addTabularDatasetColumnCheckboxes(id: String, label: String,
    columnFilter: ColumnFilter,
    selectionGroupId: String,
    required: Boolean): TabularDatasetColumnCheckboxes = {
    addTabularDatasetColumnCheckboxes(id, label,
      columnFilter,
      selectionGroupId,
      required,
      parentBoxID = None)
  }

  override def addTabularDatasetColumnCheckboxes(id: String, label: String,
    columnFilter: ColumnFilter,
    selectionGroupId: String,
    required: Boolean,
    parentBoxID: Option[String]): TabularDatasetColumnCheckboxes = {

    val columnTypeMap = getTypeMapForColumnSelector(parentBoxID, id)
    val selection: Array[String] = Try(overrideParams.getTabularDatasetSelectedColumns(id)) match {
      case Success(s) =>
        val columns = s._2.filter(_.length > 0)
        columns.map(col => this.validateColumnSelectionAndUpdateSelectionGroup(col, selectionGroupId, columnFilter, columnTypeMap))

      case _ => Array[String]()
    }
    assert(!(required && selection.isEmpty), "Multiple Column Selection Parameter:  " +
      label + " is required. But no values for " +
      " the id  \"" + id + "\" were found.")

    OperatorParameterMockUtil.addTabularColumns(operatorParametersMock, id, selection: _ *)

    class TabularDatasetColumnCheckboxesImpl extends
      AbstractCheckboxMock(availableValues = columnTypeMap.keys.toSeq,
        selected = selection, getId = id, getLabel = label, isRequired = required) with TabularDatasetColumnCheckboxes {}

    val de = new TabularDatasetColumnCheckboxesImpl
    updateDialogElements(id, de)
  }

  override def addDBTableDropdownBox(id: String, label: String, schemaBoxID: String): DBTableDropdownBox = {
    val _schemaBoxID = schemaBoxID
    // Rename to avoid complaint about recursive call.
    // DBTableDropdownBox does not use available values. We need to refactor this to not extend SingleItemSelector.
    class DBTableDropdownBoxImpl extends SingleElementSelectorMock(Seq("mockValue"), "mockValue",
      id, label) with DBTableDropdownBox

    val de = new DBTableDropdownBoxImpl
    updateDialogElements(id, de)
  }

  def addParentOperatorDropdownBox(setup: ParentOperatorSelectorSetup): ParentOperatorDropdownBox = {
    val userSet = overrideParams.getStringValue(setup.id)
    operatorParametersMock.setValue(setup.id, userSet)

    class ParentOperatorDropdownBoxMock extends
      SingleElementSelectorMock(uuids, userSet, setup.id, setup.label) with ParentOperatorDropdownBox
    val de = new ParentOperatorDropdownBoxMock()
    updateDialogElements(setup.id, de)
  }

  override def addParentOperatorDropdownBox(id: String, label: String): ParentOperatorDropdownBox = {
    addParentOperatorDropdownBox(new ParentOperatorSelectorSetup(id, label, isRequired = true))
  }

  override def addParentOperatorDropdownBox(id: String, label: String, required: Boolean): ParentOperatorDropdownBox = {
    addParentOperatorDropdownBox(new ParentOperatorSelectorSetup(id, label, required))
  }

  def addDoubleBox(setup: NumericDialogElementSetup): DoubleBox = {

    val selection: Double = Try(overrideParams.getDoubleValue(setup.id)) match {
      case Success(s) => s
      case _ => setup.defaultValue.get.toDouble
    }
    //toDo: Move this to the

    operatorParametersMock.setValue(setup.id, selection)

    class DoubleBoxImpl extends DefaultDialogElementMock(setup.id, setup.label) with DoubleBox {
      assert(selection >= setup.min.get.value && selection <= setup.max.get.value, "Selection:" +
        selection + " is not in range for integer parameter " + setup.label)
      assert(setup.min.get.inclusive || selection > setup.min.get.value, "Selection : " +
        selection + " is not in range for integer parameter " + setup.label +
        " since the min is exclusive.")
      assert(setup.max.get.inclusive || selection < setup.max.get.value, "Selection : " +
        selection + " is not in range for integer parameter " + setup.label +
        " since the max is exclusive.")
    }

    val de = new DoubleBoxImpl
    updateDialogElements(setup.id, de)
  }

  override def addDoubleBox(id: String, label: String, min: Double, max: Double,
                            inclusiveMin: Boolean, inclusiveMax: Boolean, defaultValue: Double): DoubleBox ={
    addDoubleBox(NumericDialogElementSetup(id, label, isRequired = true,
      Option.apply(NumericBound(min, inclusiveMin)), Some(NumericBound(max, inclusiveMax)),
      Option.apply(defaultValue.toString)))
  }

  def addChorusFileDropdownBox(setup: ChorusFileSelectorSetup): ChorusFileDropdown = {
    class ChorusFileDropdownImpl extends ChorusFileDropdown
    val de = new ChorusFileDropdownImpl()
    operatorParametersMock.setValue(setup.id, overrideParams.getChorusFile(setup.id))
    updateDialogElements(setup.id, de)
  }

  override def addChorusFileDropdownBox(id: String, label: String, extensionFilter: Set[String], isRequired: Boolean): ChorusFileDropdown = {
    addChorusFileDropdownBox(ChorusFileSelectorSetup(id, label, isRequired, extensionFilter, None))
  }

  override def addChorusFileDropdownBox(id: String, label: String, extensionFilter: Set[String], isRequired: Boolean, linkText: Option[String]): ChorusFileDropdown = {
    addChorusFileDropdownBox(ChorusFileSelectorSetup(id, label, isRequired, extensionFilter, linkText))
  }

  override def addAdvancedSparkSettingsBox(id: String, label: String, availableValues: List[SparkParameter]): DialogElement = {
    class AdvancedSparkSettingsBoxImpl extends DefaultDialogElementMock(id, label) with AdvancedSparkSettingsBox
    val de = new AdvancedSparkSettingsBoxImpl
    updateDialogElements(id, de)
  }

  def addScriptEditPopup(setup: ScriptEditPopupSetup): DialogElement = {
    val script = overrideParams.getStringValue(setup.id)
    operatorParametersMock.setValue(setup.id, script)
    class ScriptEditPopupImpl extends DefaultDialogElementMock(setup.id, setup.label) with ScriptEditPopup {
      if (setup.isRequired) {
        assert(script.nonEmpty, s"ScriptEditPopup element ${setup.id} is required, but has empty script.")
      }
    }
    val de = new ScriptEditPopupImpl
    updateDialogElements(setup.id, de)
  }

  override def addScriptEditPopup(id: String, label: String, scriptType: String, required: Boolean): DialogElement = {
    addScriptEditPopup(ScriptEditPopupSetup(id, label, required, scriptType))
  }

  def addRowDialog(setup: RowDialogSetup): DialogElement = {
    val userSetRows = overrideParams.getDialogRowsAsArray(setup.id)
    val nbElementsPerRow = setup.elements.length

    assert(userSetRows.map(_.getRowDialogValues.length).forall(_.equals(nbElementsPerRow)), s"RowDialogSetup ${setup.id} requires $nbElementsPerRow values per row")
    OperatorParameterMockUtil.addRowDialogElements(operatorParametersMock, setup.id, userSetRows:_*)

    class RowDialogImpl extends DefaultDialogElementMock(setup.id, setup.label) with RowDialog {
      if(setup.isRequired) {
        assert(userSetRows.nonEmpty, s"The RowDialogSetup element with id ${setup.id} is required but has no row(s) defined.")
      }
      if (setup.validator.isDefined) {
        val validation = setup.validator.get.validate(userSetRows.toList)
        assert(validation.isValid, s"Validation failed for RowDialogSetup element with id ${setup.id}: " + validation.message)
      }
    }
    val de = new RowDialogImpl
    updateDialogElements(setup.id, de)
  }
}

object OperatorDialogMock {
  @deprecated("Use constructor without tabular schema")
  def apply(params: OperatorParametersMock, input: IOBase, tabularSchema: TabularSchema) =
    new OperatorDialogMock(params, input)

  def apply(params: OperatorParametersMock, input: IOBase) =
    new OperatorDialogMock(params, input)

  @deprecated("Use constructor without tabular schema")
  def apply(params: OperatorParametersMock, input: IOBase, tabularSchema: Option[TabularSchema]) =
    new OperatorDialogMock(params, input)
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy