You are here

acquia_lift.test in Acquia Lift Connector 7.2

Same filename and directory in other branches
  1. 7.3 tests/acquia_lift.test
  2. 7 tests/acquia_lift.test

Integration tests for Acquia Lift module.

File

tests/acquia_lift.test
View source
<?php

/**
 * @file
 * Integration tests for Acquia Lift module.
 */
class AcquiaLiftWebTestBase extends DrupalWebTestCase {

  /**
   * The string to use as the JavaScript path.
   *
   * @var string
   */
  protected $liftProfileJsPath = 'some.valid.javascript.path';
  protected static $agent_plugin = 'acquia_lift_learn';
  protected $adminUser;
  protected $managerUser;
  public function setUp() {
    require_once dirname(__FILE__) . '/../includes/acquia_lift.classes.inc';
    require_once dirname(__FILE__) . '/acquia_lift.test_classes.inc';
    parent::setUp(array(
      'ctools',
      'personalize',
      'acquia_lift',
      'personalize_blocks',
    ));
    $this->adminUser = $this
      ->drupalCreateUser(array(
      'access administration pages',
      'administer personalize configuration',
    ));
    $this->managerUser = $this
      ->drupalCreateUser(array(
      'access administration pages',
      'manage personalized content',
      'administer visitor actions',
    ));
    $this
      ->configureAcquiaLiftAccount();
    $this
      ->drupalLogin($this->managerUser);
  }
  public function tearDown() {
    variable_del('acquia_lift_web_test_data');
    variable_del('acquia_lift_web_test_broken_client');
    parent::tearDown();
  }

  /**
   * Helper function to create an agent.
   */
  protected function createTestAgent($label = NULL, $options = array(), $type = 'test_agent') {
    if ($type == 'acquia_lift') {
      $options += array(
        'decision_style' => 'adaptive',
        'control_rate' => 10,
        'explore_rate' => 20,
      );
    }
    else {
      module_enable(array(
        'personalize_test',
      ));
    }
    if (empty($label)) {
      $label = $this
        ->randomName();
    }
    $agent = new stdClass();
    $agent->label = $label;
    $agent->plugin = $type;
    $agent->data = $options;
    $agent->machine_name = personalize_generate_machine_name($label, 'personalize_agent_machine_name_exists');
    $agent = personalize_agent_save($agent);
    $this
      ->resetAll();
    $agent_instance = personalize_agent_load_agent($agent->machine_name, TRUE);
    return $agent_instance;
  }

  /**
   * A helper function to create an acquia_lift_target agent.
   * @param string $label
   *   (Optional) The label for the new agent.
   * @return stdClass
   *   The newly created agent data.
   */
  protected function createTargetingAgent($label = NULL, $data = array()) {
    if (empty($label)) {
      $label = $this
        ->randomName();
    }
    $agent = new stdClass();
    $agent->label = $label;
    $agent->plugin = 'acquia_lift_target';
    $agent->data = $data;
    $agent->machine_name = personalize_generate_machine_name($label, 'personalize_agent_machine_name_exists');
    $agent = personalize_agent_save($agent);
    $this
      ->resetAll();
    $this
      ->resetAll();
    return $agent;
  }
  protected function createOptionSet($index, $optionData) {
    $option_set = array(
      'plugin' => $optionData['plugin'],
      'label' => 'Option Set ' . ($index + 1),
      'agent' => $optionData['agent'],
    );
    $options = array();
    $choice_ids = array();
    if (!isset($optionData['option_ids'])) {
      for ($j = 0; $j < $optionData['num_options']; $j++) {
        $option_id = personalize_generate_option_id($j);
        $choice_ids[] = $option_id;
        $options[$j] = array(
          'option_id' => $option_id,
          'option_label' => personalize_generate_option_label($j),
        );
      }
    }
    else {
      foreach ($optionData['option_ids'] as $i => $option_id) {
        $choice_ids[] = $option_id;
        $options[$i] = array(
          'option_id' => $option_id,
          'option_label' => personalize_generate_option_label($i),
        );
      }
    }
    $option_set['options'] = $options;
    $option_set = (object) $option_set;
    try {
      personalize_option_set_save($option_set);
    } catch (PersonalizeException $e) {
      $this
        ->fail('Exception thrown with message: . ' . $e
        ->getMessage());
    }
    return $option_set;
  }
  protected function createTargetingAgentWithNestedTest($num_options = 3, $index = 0) {
    module_load_include('inc', 'acquia_lift', 'acquia_lift.admin');

    // First, set up our agent, option set, audience and desired targeting
    // structure.
    $agent = $this
      ->createTargetingAgent();
    $this
      ->resetAll();
    $parent_option_set = $this
      ->createPersonalizedBlock($index, $agent, $num_options);
    if (empty($parent_option_set)) {
      $this
        ->fail('Could not create option set');
      return;
    }

    // Keep the option ids in an array.
    $option_ids = array();
    foreach ($parent_option_set->options as $option) {
      $option_ids[] = $option['option_id'];
    }
    $this
      ->resetAll();
    $targeting = array(
      ACQUIA_LIFT_TARGETING_EVERYONE_ELSE => $option_ids,
    );
    try {
      acquia_lift_save_targeting_structure($agent, $targeting);
    } catch (AcquiaLiftException $e) {
      $this
        ->fail('Exception thrown when none expected.');
    }

    // Now implement the targeting structure that is currently just stored in
    // the 'lift_targeting' property.
    AcquiaLiftAPI::setTestInstance();
    acquia_lift_implement_targeting($agent);
    return $agent;
  }

  /**
   * Helper that adds a target audience using two contexts AND'd together.
   *
   * @param $option_set
   * @param null $machine_name
   * @return null|string
   */
  protected function createTargetAudience($option_set, $machine_name = NULL, $contexts = array()) {
    if (empty($machine_name)) {
      $label = $this
        ->randomName();
      $machine_name = personalize_generate_machine_name($label, NULL, '-');
    }
    if (empty($contexts)) {
      $contexts = array(
        array(
          'context' => implode(PERSONALIZE_TARGETING_ADMIN_SEPARATOR, array(
            'some_plugin',
            'some_context',
          )),
          'operator' => 'contains',
          'match' => 'ohai',
        ),
        array(
          'context' => implode(PERSONALIZE_TARGETING_ADMIN_SEPARATOR, array(
            'some_plugin',
            'some_other_context',
          )),
          'operator' => 'starts',
          'match' => 'stuff',
        ),
      );
    }
    module_load_include('inc', 'acquia_lift', 'acquia_lift.admin');
    acquia_lift_target_audience_save($machine_name, $option_set->agent, $contexts, 'AND');
    $this
      ->resetAll();
    return $machine_name;
  }

  /**
   * Create personalize element option set.
   */
  protected function createPersonalizeElementsOptionSet($agent_name, $option_data) {
    $pages_link = isset($option_data['pages']) ? $option_data['pages'] : 'node';
    $preview_link = isset($option_data['preview_link']) ? $option_data['preview_link'] : $pages_link;
    $option_set = array(
      'label' => isset($option_data['label']) ? $option_data['label'] : 'Element test set 1',
      'plugin' => 'elements',
      'agent' => $agent_name,
      'executor' => 'personalizeElements',
      'options' => array(),
      'data' => array(
        'personalize_elements_selector' => isset($option_data['selector']) ? $option_data['selector'] : '#some-selector',
        'personalize_elements_type' => isset($option_data['type']) ? $option_data['type'] : 'editText',
        'pages' => $pages_link,
      ),
      'preview_link' => $preview_link,
    );
    if (!empty($option_data['add_control'])) {
      $option_set['options'][] = array(
        'option_label' => PERSONALIZE_CONTROL_OPTION_LABEL,
        'option_id' => PERSONALIZE_CONTROL_OPTION_ID,
        'personalize_elements_content' => '',
      );
    }
    $num_options = empty($option_data['num_options']) ? 2 : $option_data['num_options'];
    for ($i = 0; $i < $num_options; $i++) {
      $option_set['options'][] = array(
        'option_id' => personalize_generate_option_id($i),
        'option_label' => personalize_generate_option_label($i),
        'personalize_elements_content' => 'Generated content ' . ($i + 1),
      );
    }
    return personalize_option_set_save((object) $option_set);
  }

  /**
   * Creates a user profile field which can be used for targeting.
   *
   * @return array
   *   An associative array representing the field.
   */
  protected function createUserProfileField($field_name = NULL) {
    $field_name = $field_name ?: $this
      ->randomName();
    $field = array(
      'field_name' => 'field_' . drupal_strtolower($field_name),
      'type' => 'text',
      'cardinality' => 1,
    );
    field_create_field($field);
    $fieldInstance = array(
      'field_name' => $field['field_name'],
      'entity_type' => 'user',
      'bundle' => 'user',
      'settings' => array(
        'user_register_form' => FALSE,
      ),
    );
    field_create_instance($fieldInstance);
    return $field;
  }

  /**
   * Adds a personalizable field to the article node type.
   */
  protected function createPersonalizedArticleField() {

    // Add personalizable field to the article node type.
    $field = array(
      'type' => 'text',
      'field_name' => 'article_headline',
      'cardinality' => -1,
      'settings' => array(
        'personalize' => array(
          'enabled' => 1,
          'agent_type' => 'acquia_lift_target',
          'options' => array(),
          'create_goal' => 1,
        ),
      ),
    );
    field_create_field($field);
    $instance = array(
      'field_name' => 'article_headline',
      'entity_type' => 'node',
      'label' => 'Personalizable Headline',
      'bundle' => 'article',
      'required' => FALSE,
    );
    field_create_instance($instance);
  }

  /**
   * Creates an article node with a personalized headline field.
   */
  protected function createPersonalizedField() {
    AcquiaLiftAPI::setTestInstance();

    // Create a node which we will attach a fields-based option set to. We can't
    // do this via the form because of the way we alter the form, which makes the
    // "Add an option" button not findable by simpletest.
    $node = new stdClass();
    $node->type = 'article';
    $node->language = LANGUAGE_NONE;
    node_object_prepare($node);
    $node->title = $this
      ->randomName();
    $node->article_headline['und'][0] = array(
      'value' => 'first value',
    );
    $node->article_headline['und'][1] = array(
      'value' => 'second value',
    );
    node_save($node);

    // Now create the option set.
    $option_set = new stdClass();
    $option_set->is_new = TRUE;
    $option_set->data = array();
    $option_set->options = array();
    $option_set->plugin = 'fields';
    $option_set->new_agent_title = 'Article: Personalizable Headline';
    $option_set->options = array(
      array(
        'option_label' => personalize_fields_generate_option_label(0, array(
          'value' => 'first value',
        )),
      ),
      array(
        'option_label' => personalize_fields_generate_option_label(1, array(
          'value' => 'second value',
        )),
      ),
    );
    if (personalize_fields_option_set_prepare($option_set, 'node', $node->nid, $node, 'article_headline')) {
      personalize_fields_option_set_save($option_set, 'node', $node->nid, 'article_headline');
    }
    $this
      ->resetAll();
    $agent_name = $option_set->agent;
    return array(
      $node,
      $option_set,
      $agent_name,
    );
  }

  /**
   * Helper method to move buttons names to one pace to simplify
   * it's maintaining
   *
   * Kind of Page Objects Patterns
   *
   * @param $type string
   * @return string
   */
  protected function getButton($type = '', $context = array()) {
    switch ($type) {
      case 'wizard_next':
        module_load_include('inc', 'personalize', 'personalize.admin.campaign');
        $agent_instance = NULL;
        if (isset($context['agent_name'])) {
          $agent_instance = personalize_agent_load_agent($context['agent_name']);
        }
        $steps = _personalize_campaign_wizard_steps($agent_instance);
        $next_step = _personalize_campaign_wizard_next_step(array(
          'storage' => array(
            'step' => $context['step'],
          ),
        ), $agent_instance);
        $next_info = $steps[$next_step];
        $button_text = 'Next: ' . $next_info['preview_message'];
        return t($button_text);
      case 'wizard_save':
      case 'wizard_done':
        return t('Save');
      case 'wizard_start':
        return t('Start');
      case 'wizard_element_navigate':
        return t('Go');
      case 'create_campaign':
        return t('Create and edit');
      case 'delete':
        return t('Delete');
      case 'config':
        return t('Save configuration');
      default:
        return t('Save');
    }
  }

  /**
   * Helper method to configure an Acquia Lift account.
   */
  protected function configureAcquiaLiftAccount() {

    // Set the subscription data variable.
    variable_set('acquia_subscription_data', array(
      'active' => TRUE,
      'heartbeat_data' => array(
        'acquia_lift' => array(
          'status' => TRUE,
          'decision' => array(
            'public_key' => 'some-public-key',
            'private_key' => 'some-private-key',
            'api_url' => 'api.example.com',
          ),
          'profile' => array(
            'js_path' => 'acquia_lift_profiles.example.com/path/to.js',
            'account_name' => 'MYALPROFILESACCOUNT',
            'hostname' => 'web-api.example.com',
            'private_key' => 'abc123',
            'secret_key' => 'xyz987',
          ),
        ),
      ),
    ));
  }

  /**
   * Creates the required number of custom blocks.
   *
   * @param int $num
   *   The number of blocks to create.
   *
   * @return array
   *   An array of block deltas for use in personalized blocks.
   */
  protected function createPersonalizedBlock($index, $agent, $num_options = 2) {
    $option_set = array(
      'plugin' => 'block',
      'label' => 'Option Set ' . ($index + 1),
      'agent' => $agent->machine_name,
      'data' => array(
        'block_title' => 'Personalized Block ' . ($index + 1),
      ),
    );
    $options = array();
    module_load_include('inc', 'personalize_blocks', 'personalize_blocks.admin');
    for ($i = 1; $i <= $num_options; $i++) {
      $title = t('Custom block @num from @index', array(
        '@num' => $i,
        '@index' => $index,
      ));
      $values = array(
        'title' => $title,
        'info' => $title,
        'body' => array(
          'format' => 'filtered_html',
          'value' => 'Some value',
        ),
      );
      $option = array(
        'option_label' => 'Option ' . $i,
        'option_id' => 'option-' . $i,
        'bid' => _personalize_blocks_add_custom_block($values),
      );
      $options[] = $option;
    }
    $option_set['options'] = $options;
    $option_set = (object) $option_set;
    try {
      personalize_option_set_save($option_set);
    } catch (PersonalizeException $e) {
      $this
        ->fail('Exception thrown with message: . ' . $e
        ->getMessage());
      return NULL;
    }
    return $option_set;
  }
  function createTestFromOptionSet($agent_data, $option_set) {
    module_load_include('inc', 'acquia_lift', 'acquia_lift.admin');
    $option_ids = array();
    foreach ($option_set->options as $option) {
      $option_ids[] = $option['option_id'];
    }
    acquia_lift_save_targeting_structure($agent_data, array(
      ACQUIA_LIFT_TARGETING_EVERYONE_ELSE => $option_ids,
    ));
  }

}
class AcquiaLiftWebTestConfig extends AcquiaLiftWebTestBase {
  public static function getInfo() {
    return array(
      'name' => t('Acquia Lift Web Tests - Configuration'),
      'description' => t('Tests related to configuring Acquia Lift.'),
      'group' => t('Personalize'),
    );
  }
  public function testLiftAgentAvailability() {

    // Fill all required information.
    $this
      ->configureAcquiaLiftAccount();

    // Remove the JavaScript path.
    variable_del('acquia_subscription_data');
    $this
      ->resetAll();

    // Try to add a new campaign and verify that the Acquia Lift agent isn't presented.
    $this
      ->drupalLogin($this->managerUser);
    $this
      ->drupalGet('admin/structure/personalize/add');
    $this
      ->assertText(t('Your Acquia Lift account info has not been configured.'));

    // Fill all required information.
    $this
      ->configureAcquiaLiftAccount();

    // Now confirm that Acquia Lift is an option for new campaigns.
    $this
      ->drupalLogin($this->managerUser);
    $this
      ->drupalGet('admin/structure/personalize/add');
    $this
      ->assertNoText(t('Your Acquia Lift account info has not been configured.'));
  }
  function testPersonalizeElementsConfigurationIntegration() {
    $fullAdminUser = $this
      ->drupalCreateUser(array(
      'access administration pages',
      'administer personalize configuration',
      'use advanced personalize elements features',
    ));
    $this
      ->drupalLogin($fullAdminUser);

    // Test edit in context settings added to personalize elements configuration form.
    $this
      ->drupalGet('admin/config/content/personalize/personalize-elements');

    // Should be initially set to 1.
    $this
      ->assertFieldChecked('edit-acquia-lift-html-context-strip');
    $edit = array(
      'acquia_lift_html_context_strip' => FALSE,
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('config'));

    // Check the javascript setting.
    $this
      ->drupalLogin($this->managerUser);
    $this
      ->drupalGet('');
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertEqual($settings['acquia_lift']['edit_in_context_html_strip'], 0);

    // Set it back.
    $this
      ->drupalLogin($fullAdminUser);
    $edit = array(
      'acquia_lift_html_context_strip' => TRUE,
    );
    $this
      ->drupalPost('admin/config/content/personalize/personalize-elements', $edit, $this
      ->getButton('config'));

    // Check that the JavaScript settings changed.
    $this
      ->drupalLogin($this->managerUser);
    $this
      ->drupalGet('');
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertEqual($settings['acquia_lift']['edit_in_context_html_strip'], 1);
  }

}
class AcquiaLiftWebTestVariationSets extends AcquiaLiftWebTestBase {
  public static function getInfo() {
    return array(
      'name' => t('Acquia Lift Web Tests - Variation Sets'),
      'description' => t('Tests functionality related to variation set creation.'),
      'group' => t('Personalize'),
    );
  }
  function testPersonalizeBlockRedirection() {

    // Create a new agent
    $agent = $this
      ->createTestAgent();

    // Create a personalized block from the form with a destination in the
    // url query string.
    $this
      ->drupalGet('/admin/structure/personalize/variations/personalize-blocks/add', array(
      'query' => array(
        'destination' => 'node',
      ),
    ));
    $edit = array(
      'agent_select' => $agent
        ->getMachineName(),
      'title' => 'My test block',
      'blocks[0][option_label]' => 'Option A',
      'blocks[0][block][bid]' => 'comment_delta_recent',
      'blocks[1][option_label]' => 'Option B',
      'blocks[1][block][bid]' => 'system_delta_main',
    );
    $this
      ->drupalPost(NULL, $edit, t('Save'));

    // Verify that the user is redirected to the original page with a custom
    // URL query parameter.
    $this
      ->assertUrl('node', array(
      'query' => array(
        'liftpm' => 'new_block|My test block',
      ),
    ));

    // Verify that the pending message has been added to the settings.
    $expected_message = t('Created the new <em class="placeholder">My test block</em> personalized block. The block will not appear on your website until you add the block to a region on the !blocks page.', array(
      '!blocks' => l('Structure > Blocks', 'admin/structure/blocks'),
    ));
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertEqual($settings['acquia_lift']['pendingMessage'], array(
      $expected_message,
    ));
  }

}
class AcquiaLiftWebTestAgentAdmin extends AcquiaLiftWebTestBase {
  public static function getInfo() {
    return array(
      'name' => t('Acquia Lift Web Tests - Agent Administration'),
      'description' => t('Tests functionality of adminstering Acquia Lift agents and their components.'),
      'group' => t('Personalize'),
    );
  }
  function testCreateAgent() {
    $this
      ->configureAcquiaLiftAccount();

    // Enable the test module that provides multiple agent types.
    module_enable(array(
      'personalize_test_extra_agent',
    ));
    $this
      ->resetAll();

    // Need to call resetAll again to force ctools to load the class files.
    $this
      ->resetAll();

    // Go to the agent creation page and assert there is no agent type dropdown
    // even with multiple agent types enabled.
    $this
      ->drupalLogin($this->managerUser);
    $this
      ->drupalGet('admin/structure/personalize/add');
    $this
      ->assertNoFieldByName('agent_basic_info[agent_type]');
    $this
      ->drupalPost(NULL, array(
      'agent_basic_info[title]' => $this
        ->randomName(),
    ), $this
      ->getButton('create_campaign'));
    $url = $this
      ->getUrl();
    $pattern = '/admin\\/structure\\/personalize\\/manage\\/([a-z0-9\\_\\-]+)\\//';
    preg_match($pattern, $url, $matches);
    $agent = personalize_agent_load($matches[1]);
    $this
      ->assertEqual(ACQUIA_LIFT_TARGETING_AGENT, $agent->plugin);

    // In Campaign list page, Draft campaign does not have a Start button, but a "Review and start" link.
    $this
      ->drupalGet('admin/structure/personalize');
    $this
      ->assertLink(t('Review and start'));
    $this
      ->assertNoFieldByXPath('//form[@id="personalize-change-status-' . $agent->machine_name . '-form"]//input[@value="' . t('Start') . '"]');
  }
  function testAgentList() {
    module_disable(array(
      'personalize_test',
    ));
    $admin_user = $this
      ->drupalCreateUser(array(
      'access administration pages',
      'manage personalized content',
    ));
    $this
      ->drupalLogin($admin_user);

    // There should just be a message saying there are no agents.
    $this
      ->drupalGet('admin/structure/personalize');
    $this
      ->assertText(t('To create your first new personalization, click the above Add Personalization link.'));
    $this
      ->assertNoRaw('<h3>Draft</h3>');
    $this
      ->assertNoRaw('<h3>Scheduled</h3>');
    $this
      ->assertNoRaw('<h3>Running</h3>');
    $this
      ->assertNoRaw('<h3>Paused</h3>');
    $this
      ->assertNoRaw('<h3>Completed</h3>');

    // An agent without any variations should have a link to edit and delete
    // but not for reports.
    $agent = $this
      ->createTargetingAgent();
    $this
      ->drupalGet('admin/structure/personalize');
    $this
      ->assertNoText(t('No personalizations available.'));
    $this
      ->assertLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
    $this
      ->assertLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/delete');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/results');
    $this
      ->assertRaw('<h3>Draft</h3>');
    $this
      ->assertNoRaw('<h3>Scheduled</h3>');
    $this
      ->assertNoRaw('<h3>Running</h3>');
    $this
      ->assertNoRaw('<h3>Paused</h3>');
    $this
      ->assertNoRaw('<h3>Completed</h3>');

    // Add a variation set and create a test.
    $option_set = $this
      ->createPersonalizedBlock(0, $agent, 3);
    $this
      ->createTestFromOptionSet($agent, $option_set);
    $this
      ->drupalGet('admin/structure/personalize');
    $this
      ->assertLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/delete');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/results');
    $this
      ->assertText(t('Test only'));
    $this
      ->assertText(t('Everyone'));

    // No link to complete this test because it hasn't been started yet.
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/everyone-else/complete');

    // Add two audiences and assign variations so that there is only targeting.
    $audience_1 = personalize_generate_machine_name($this
      ->randomName(), NULL, '-');
    $this
      ->createTargetAudience($option_set, $audience_1);
    $audience_2 = personalize_generate_machine_name($this
      ->randomName(), NULL, '-');
    $this
      ->createTargetAudience($option_set, $audience_2);
    $targeting = array(
      $audience_1 => array(
        'option-1',
      ),
      $audience_2 => array(
        'option-2',
      ),
      ACQUIA_LIFT_TARGETING_EVERYONE_ELSE => array(
        'option-3',
      ),
    );
    acquia_lift_save_targeting_structure($agent, $targeting);
    $this
      ->drupalGet('admin/structure/personalize');
    $this
      ->assertLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/delete');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/results');
    $this
      ->assertText(t('Target only'));
    $this
      ->assertText($audience_1);
    $this
      ->assertText($audience_2);
    $this
      ->assertText(t('Everyone else'));
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/' . $audience_1 . '/complete');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/' . $audience_2 . '/complete');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/everyone-else/complete');

    // Adjust variations so that there is testing and targeting.
    $targeting = array(
      $audience_1 => array(
        'option-1',
        'option-2',
      ),
      $audience_2 => array(
        'option-2',
      ),
      ACQUIA_LIFT_TARGETING_EVERYONE_ELSE => array(
        'option-3',
      ),
    );
    acquia_lift_save_targeting_structure($agent, $targeting);
    $this
      ->drupalGet('admin/structure/personalize');
    $this
      ->assertLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/delete');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/results');
    $this
      ->assertText(t('Test and target'));
    $this
      ->assertText($audience_1);
    $this
      ->assertText($audience_2);
    $this
      ->assertText(t('Everyone else'));
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/' . $audience_1 . '/complete');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/' . $audience_2 . '/complete');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/everyone-else/complete');

    // Schedule and check heading.
    personalize_agent_set_start_date($agent->machine_name, time() + 86400);
    personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_SCHEDULED);
    $this
      ->drupalGet('admin/structure/personalize');
    $this
      ->assertLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/delete');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/results');
    $this
      ->assertNoRaw('<h3>Draft</h3>');
    $this
      ->assertRaw('<h3>Scheduled</h3>');
    $this
      ->assertNoRaw('<h3>Running</h3>');
    $this
      ->assertNoRaw('<h3>Paused</h3>');
    $this
      ->assertNoRaw('<h3>Completed</h3>');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/' . $audience_1 . '/complete');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/' . $audience_2 . '/complete');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/everyone-else/complete');

    // Set it to running and check that the reporting link is now available
    // and that the campaign is shown in the correct section.
    personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_RUNNING);
    $this
      ->drupalGet('admin/structure/personalize');
    $this
      ->assertLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/delete');
    $this
      ->assertLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/results');
    $this
      ->assertLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/results?targeting_audience=' . $audience_1);
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/results?targeting_audience=' . $audience_2);
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/results?targeting_audience=' . ACQUIA_LIFT_TARGETING_EVERYONE_ELSE);
    $this
      ->assertLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/' . $audience_1 . '/complete');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/' . $audience_2 . '/complete');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/everyone-else/complete');
    $this
      ->assertNoRaw('<h3>Draft</h3>');
    $this
      ->assertNoRaw('<h3>Scheduled</h3>');
    $this
      ->assertRaw('<h3>Running</h3>');
    $this
      ->assertNoRaw('<h3>Paused</h3>');
    $this
      ->assertNoRaw('<h3>Completed</h3>');

    // Pause and check heading.
    personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_PAUSED);
    $this
      ->drupalGet('admin/structure/personalize');
    $this
      ->assertNoRaw('<h3>Draft</h3>');
    $this
      ->assertNoRaw('<h3>Scheduled</h3>');
    $this
      ->assertNoRaw('<h3>Running</h3>');
    $this
      ->assertRaw('<h3>Paused</h3>');
    $this
      ->assertNoRaw('<h3>Completed</h3>');
    $this
      ->assertLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/' . $audience_1 . '/complete');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/' . $audience_2 . '/complete');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/everyone-else/complete');

    // Complete and check heading.
    personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_COMPLETED);
    $this
      ->drupalGet('admin/structure/personalize');
    $this
      ->assertNoRaw('<h3>Draft</h3>');
    $this
      ->assertNoRaw('<h3>Scheduled</h3>');
    $this
      ->assertNoRaw('<h3>Running</h3>');
    $this
      ->assertNoRaw('<h3>Paused</h3>');
    $this
      ->assertRaw('<h3>Completed</h3>');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/' . $audience_1 . '/complete');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/' . $audience_2 . '/complete');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/everyone-else/complete');
  }

}
class AcquiaLiftWebTestFundamentals extends AcquiaLiftWebTestBase {
  public static function getInfo() {
    return array(
      'name' => t('Acquia Lift Web Tests - Fundamentals'),
      'description' => t('Tests the module\'s underlying machinery.'),
      'group' => t('Personalize'),
    );
  }

  /**
   * Tests that new agents on the site cannot override existing agents in Lift.
   */
  public function testMachineNameValidation() {
    $agent = new stdClass();
    $agent->title = 'my-existing-agent';
    $agent->id = 'my-existing-agent';
    $agent->algorithm = 'bernoulli';
    $agent->created = "4605-05-17T10:47:17.530Z";
    $agent->decisions_sets = array();
    $agent->goals = array();
    $test_data = array(
      'campaigns' => array(
        $agent,
      ),
    );
    variable_set('acquia_lift_web_test_data', $test_data);
    AcquiaLiftAPI::setTestInstance();

    // Try to create a new agent with the same name as one that exists in Lift.
    $this
      ->createTestAgent('my-existing-agent', array(
      'control_rate' => 10,
      'explore_rate' => 30,
    ), self::$agent_plugin);
    $this
      ->resetAll();
    $agent = personalize_agent_load_agent('my-existing-agent');
    $this
      ->assertNull($agent);
    $agent = personalize_agent_load_agent('my-existing-agent-0');
    $this
      ->assertTrue($agent instanceof AcquiaLiftLearningAgentInterface);
  }
  public function testSiteNamePrefixOnSave() {

    // We want to simulate an agent that existed before the site_name attribute
    // was being added on presave of new agents, so we insert one directly into
    // the db.
    $options = array(
      'decision_style' => 'adaptive',
      'control_rate' => 10,
      'explore_rate' => 20,
    );
    $label = $this
      ->randomName();
    $machine_name = personalize_generate_machine_name($label, 'personalize_agent_machine_name_exists');
    db_insert('personalize_agent')
      ->fields(array(
      'machine_name' => $machine_name,
      'plugin' => self::$agent_plugin,
      'started' => 1407499650,
      'label' => $label,
      'data' => serialize($options),
    ))
      ->execute();
    $agent = personalize_agent_load($machine_name, TRUE);
    $this
      ->assertFalse(isset($agent->data['site_name']));

    // Now resave the agent - it still should not get a site_name added.
    personalize_agent_save($agent);
    $this
      ->resetAll();
    $agent = personalize_agent_load($machine_name, TRUE);
    $this
      ->assertFalse(isset($agent->data['site_name']));

    // Now create a new agent via personalize_agent_save(). It should get the
    // site name property.
    $agent2 = new stdClass();
    $label2 = $this
      ->randomName();
    $machine_name2 = personalize_generate_machine_name($label2, 'personalize_agent_machine_name_exists');
    $agent2->label = $label2;
    $agent2->plugin = self::$agent_plugin;
    $agent2->data = $options;
    $agent2->machine_name = $machine_name2;
    AcquiaLiftAPI::setTestInstance();
    personalize_agent_save($agent2);
    $this
      ->resetAll();
    $agent2 = personalize_agent_load($machine_name2, TRUE);
    $this
      ->assertEqual('drupal', $agent2->data['site_name']);
  }
  function testSiteNamePrefixAttach() {
    AcquiaLiftAPI::setTestInstance();
    $agent = $this
      ->createTargetingAgentWithNestedTest(2);
    $this
      ->resetAll();
    module_load_include('inc', 'acquia_lift', 'acquia_lift.batch');
    $operations = acquia_lift_get_sync_operations_for_agent($agent);

    // The operations array will have 3 items - saveDecisionSets, saveGoal, and
    // saveCampaign, in that order. Confir the site prefix was attached to the
    // decision set and goal names.
    $decision_set_op = $operations[0];
    $goal_op = $operations[1];
    $this
      ->assertTrue(strpos($decision_set_op['args'][0], 'drupal-') === 0);
    $this
      ->assertTrue(strpos($goal_op['args'][0], 'drupal-') === 0);

    // Now set the Lift Web customer site name.
    variable_set('acquia_lift_profiles_site_name', 'My Test Site');
    $this
      ->resetAll();
    $new_agent = $this
      ->createTargetingAgentWithNestedTest(2, 1);
    $this
      ->resetAll();
    $operations = acquia_lift_get_sync_operations_for_agent($new_agent);

    // Check that the new site name is prepended to the componenents.
    $decision_set_op = $operations[0];
    $goal_op = $operations[1];
    $this
      ->assertTrue(strpos($decision_set_op['args'][0], 'my-test-site-') === 0);
    $this
      ->assertTrue(strpos($goal_op['args'][0], 'my-test-site-') === 0);

    // Now output the personalization and check the js settings.
    // Now let's place our personalized block and confirm that the settings are
    // still as they should be.
    $admin_user = $this
      ->drupalCreateUser(array(
      'access administration pages',
      'manage personalized content',
      'administer blocks',
    ));
    $this
      ->drupalLogin($admin_user);
    $option_set = acquia_lift_get_option_set_for_targeting($new_agent->machine_name);
    $edit = array(
      'blocks[personalize_blocks_' . $option_set->osid . '][region]' => 'content',
    );
    $this
      ->drupalPost('admin/structure/block', $edit, t('Save blocks'));
    $this
      ->drupalLogout();
    $this
      ->drupalGet('');
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertEqual('my-test-site-', $settings['acquia_lift_target']['agent_map'][$new_agent->machine_name . '-test']['site_name_prefix']);

    // Now set the Lift Web customer site name to empty string.
    variable_set('acquia_lift_profiles_site_name', '');
    $this
      ->resetAll();
    $new_agent = $this
      ->createTargetingAgentWithNestedTest(2, 2);
    $this
      ->resetAll();
    $operations = acquia_lift_get_sync_operations_for_agent($new_agent);

    // Check that no dash is prepended to the componenents.
    $decision_set_op = $operations[0];
    $goal_op = $operations[1];
    $this
      ->assertTrue(substr($decision_set_op['args'][0], 0, 1) !== '-');
    $this
      ->assertTrue(substr($goal_op['args'][0], 0, 1) !== '-');
  }

  /**
   * Tests the function that gathers operations for syncing of agents and their
   * components to Lift.
   */
  public function testBatchSyncOperations() {
    AcquiaLiftAPI::setTestInstance();
    module_load_include('inc', 'acquia_lift', 'acquia_lift.batch');

    // Create a targeting agent with a single nested test.
    $agent = $this
      ->createTargetingAgentWithNestedTest(4);
    personalize_goal_save($agent->machine_name, 'user_login', 1);
    $this
      ->resetAll();
    $test_agents = personalize_agent_load_by_type(ACQUIA_LIFT_TESTING_AGENT);
    $test_agent = reset($test_agents);
    $os = personalize_option_set_load_by_agent($test_agent->machine_name);
    $sub_option_set = reset($os);

    // Add a couple of tests for deletion to ensure they show up in the batch
    // operations.
    $agent->tests_to_delete = array(
      'first-test',
      'second-test',
    );
    $operations = acquia_lift_get_sync_operations_for_agent($agent);
    $decision_name = 'drupal-osid-' . $sub_option_set->osid;
    $expected_operations = array(
      array(
        'method' => 'deleteAgent',
        'args' => array(
          'first-test',
        ),
      ),
      array(
        'method' => 'deleteAgent',
        'args' => array(
          'second-test',
        ),
      ),
      array(
        'method' => 'saveDecisionSet',
        'args' => array(
          $decision_name,
          'Sub-test for ' . $agent->label,
          array(
            array(
              'option_id' => 'option-1',
            ),
            array(
              'option_id' => 'option-2',
            ),
            array(
              'option_id' => 'option-3',
            ),
            array(
              'option_id' => 'option-4',
            ),
          ),
        ),
      ),
      array(
        'method' => 'saveGoal',
        'args' => array(
          'drupal-clicks_option_set_1',
        ),
      ),
      array(
        'method' => 'saveGoal',
        'args' => array(
          'drupal-user_login',
        ),
      ),
      array(
        'method' => 'saveCampaign',
        'args' => array(
          $test_agent->machine_name,
          'Sub-test for ' . $agent->label,
          $decision_name,
          array(
            'drupal-clicks_option_set_1',
            'drupal-user_login',
          ),
          FALSE,
          0,
          1,
        ),
      ),
    );
    $this
      ->assertEqual($expected_operations, $operations);
  }
  function createTestFromOptionSet($agent_data, $option_set) {
    module_load_include('inc', 'acquia_lift', 'acquia_lift.admin');
    $option_ids = array();
    foreach ($option_set->options as $option) {
      $option_ids[] = $option['option_id'];
    }
    acquia_lift_save_targeting_structure($agent_data, array(
      ACQUIA_LIFT_TARGETING_EVERYONE_ELSE => $option_ids,
    ));
  }

}
class AcquiaLiftWebTestReports extends AcquiaLiftWebTestBase {
  public static function getInfo() {
    return array(
      'name' => t('Acquia Lift Web Tests - Reporting'),
      'description' => t('Tests the reporting functionality for Acquia Lift.'),
      'group' => t('Personalize'),
    );
  }
  public function setUp() {
    parent::setUp();
    $this
      ->configureAcquiaLiftAccount();
  }
  public function testReportPage() {

    // Test that a report page shows up for a personalization with a single test.
    $this
      ->drupalLogin($this->managerUser);
    $agent = $this
      ->createTargetingAgent();
    $option_set = $this
      ->createPersonalizedBlock(0, $agent, 3);
    $option_ids = array();
    foreach ($option_set->options as $option) {
      $option_ids[] = $option['option_id'];
    }
    $targeting = array(
      ACQUIA_LIFT_TARGETING_EVERYONE_ELSE => array(
        $option_ids[0],
        $option_ids[1],
        $option_ids[2],
      ),
    );
    try {
      acquia_lift_save_targeting_structure($agent, $targeting);
    } catch (AcquiaLiftException $e) {
      $this
        ->fail('Exception thrown when none expected.');
    }

    // Now implement the targeting structure and set the agent to running.
    AcquiaLiftAPI::setTestInstance();
    acquia_lift_implement_targeting($agent);
    personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_RUNNING);
    $this
      ->resetAll();
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/results');
    $this
      ->assertText('Everyone audience');
    $this
      ->assertNoFieldByName('audience_filter');
    $this
      ->assertLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/everyone-else/complete');

    // Pause the agent and change it so that it has another test.
    personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_PAUSED);
    $this
      ->resetAll();
    $contexts = array(
      array(
        'context' => implode(PERSONALIZE_TARGETING_ADMIN_SEPARATOR, array(
          'some_plugin',
          'some_context',
        )),
        'operator' => 'contains',
        'match' => 'ohai',
      ),
    );
    acquia_lift_target_audience_save('My First Audience', $agent->machine_name, $contexts, 'OR', 50, 'my-first-audience');
    $targeting['my-first-audience'] = array(
      $option_ids[1],
      $option_ids[2],
    );
    acquia_lift_save_targeting_structure($agent, $targeting);

    // Now implement the targeting structure and set the agent to running.
    AcquiaLiftAPI::setTestInstance();
    acquia_lift_implement_targeting($agent);
    personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_RUNNING);
    $this
      ->resetAll();
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/results');
    $this
      ->assertNoText('Test for Everyone else audience');
    $this
      ->assertFieldByName('audience_filter');
    $this
      ->assertOptionSelected('acquia-lift-report-audience-filter', 'active|everyone-else');
    $this
      ->assertLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/everyone-else/complete');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/my-first-audience/complete');

    // Now change the audience and verify that the complete button changes
    $edit = array(
      'audience_filter' => 'active|my-first-audience',
    );
    $this
      ->drupalPostAJAX(NULL, $edit, 'audience_filter');
    $this
      ->assertFieldByName('audience_filter');
    $this
      ->assertOptionSelected('acquia-lift-report-audience-filter', 'active|my-first-audience');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/everyone-else/complete');
    $this
      ->assertLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/my-first-audience/complete');

    // Change it again so that it has no tests.
    personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_PAUSED);
    $this
      ->resetAll();
    $contexts = array(
      array(
        'context' => implode(PERSONALIZE_TARGETING_ADMIN_SEPARATOR, array(
          'some_plugin',
          'some_context',
        )),
        'operator' => 'contains',
        'match' => 'kthxbai',
      ),
    );
    acquia_lift_target_audience_save('My Second Audience', $agent->machine_name, $contexts, 'OR', 10, 'my-second-audience');
    $targeting = array(
      ACQUIA_LIFT_TARGETING_EVERYONE_ELSE => array(
        $option_ids[0],
      ),
      'my-first-audience' => array(
        $option_ids[1],
      ),
      'my-second-audience' => array(
        $option_ids[2],
      ),
    );
    acquia_lift_save_targeting_structure($agent, $targeting);

    // Now implement the targeting structure and set the agent to running.
    AcquiaLiftAPI::setTestInstance();
    acquia_lift_implement_targeting($agent);
    personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_RUNNING);
    $this
      ->resetAll();
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/results');
    $this
      ->assertFieldByName('audience_filter');
    $targeting_option_set = acquia_lift_get_option_set_for_targeting($agent->machine_name);
    $fallback_audience = acquia_lift_get_fallback_audience_name(array_keys($targeting_option_set->targeting));

    // Only retired tests shown in the filter.
    $retired = acquia_lift_get_retired_tests($agent->machine_name);
    $this
      ->assertEqual(count($retired), 2);
    $this
      ->assertOptionSelected('acquia-lift-report-audience-filter', 'active|' . $fallback_audience);
    $this
      ->assertNoOptionSelected('acquia-lift-report-audience-filter', 'retired|' . $retired[0]->machine_name);
    $this
      ->assertNoOptionSelected('acquia-lift-report-audience-filter', 'retired|' . $retired[1]->machine_name);

    // No link to complete test.
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/everyone-else/complete');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/my-first-audience/complete');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $agent->machine_name . '/audience/my-second-audience/complete');
  }

  /*  public function testConversionReportAjaxEndpoint() {
      $this->drupalLogin($this->managerUser);
      $agent = $this->createTargetingAgent();
      $option_set = $this->createPersonalizedBlock(0, $agent, 3);
      $option_ids = array();
      foreach ($option_set->options as $option) {
        $option_ids[] = $option['option_id'];
      }

      $targeting = array(
        ACQUIA_LIFT_TARGETING_EVERYONE_ELSE => array($option_ids[0], $option_ids[1], $option_ids[2])
      );
      acquia_lift_save_targeting_structure($agent, $targeting);
      // Now implement the targeting structure and set the agent to running.
      AcquiaLiftAPI::setTestInstance();
      acquia_lift_implement_targeting($agent);
      personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_RUNNING);
      $this->resetAll();
      $nested = acquia_lift_get_nested_tests($agent);
      $nested_agent = personalize_agent_load(reset($nested));
      // Set the agent to read report data from the test file.
      $path = drupal_get_path('module', 'acquia_lift');
      variable_set("acquia_lift_report_source_" . $nested_agent->machine_name, "/" . $path . '/tests/test_report.json');

      // Call the conversion report endpoint.
      $first_osid = 'osid-1';
      $report = $this->drupalGet('acquia_lift/reports/conversion', array('query' => array(
        'personalization' => $agent->machine_name,
        'audience' => ACQUIA_LIFT_TARGETING_EVERYONE_ELSE,
      )));

      $report = drupal_json_decode($report);

      $pattern = '/class="lift-statistic-category"/';
      preg_match($pattern, $report, $matches);
      $this->assertEqual(count($matches), 1, 'Only one category of results returned.');

      $pattern = '/(<table)/';
      preg_match($pattern, $report, $matches);
      $this->assertEqual(count($matches), 2, 'Only two tables returned.');

      $pattern = '/data-acquia-lift-campaign=\"([a-z0-9\_\-]+)\"/';
      preg_match($pattern, $report, $matches);

      $this->assertEqual($matches[1], $agent->machine_name, 'Personalization name was passed in tabular data.');

      $pattern = '/data-acquia-lift-decision-name=\"([a-z0-9\_\-]+)\"/';
      preg_match($pattern, $report, $matches);
      $this->assertEqual($matches[1], $first_osid, 'Decision name was passed in tabular data.');
    }*/
  function testReportEndDate() {
    $this
      ->drupalLogin($this->managerUser);
    $agent = $this
      ->createTargetingAgent();
    $option_set = $this
      ->createPersonalizedBlock(0, $agent, 3);
    $option_ids = array();
    foreach ($option_set->options as $option) {
      $option_ids[] = $option['option_id'];
    }
    $targeting = array(
      ACQUIA_LIFT_TARGETING_EVERYONE_ELSE => array(
        $option_ids[0],
        $option_ids[1],
        $option_ids[2],
      ),
    );
    acquia_lift_save_targeting_structure($agent, $targeting);

    // Now implement the targeting structure and set the agent to running.
    AcquiaLiftAPI::setTestInstance();
    acquia_lift_implement_targeting($agent);
    personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_RUNNING);
    $this
      ->resetAll();
    $nested = acquia_lift_get_nested_tests($agent);
    $nested_agent = personalize_agent_load(reset($nested));

    // We need to bypass the personalize_agent_set_status() function because it
    // does the verification check, which would fail.
    variable_set(_personalize_agent_get_status_variable($agent->machine_name), PERSONALIZE_STATUS_RUNNING);

    // Set the started time of the agent to 48 hours ago.
    $started = time() - 48 * 60 * 60;
    $agent->started = $started;
    personalize_agent_save($agent);

    // Add some dummy report data to be returned by the API.
    $test_data = array(
      // Now add the reports.
      'reports' => array(
        $nested_agent->machine_name => AcquiaLiftTestReports::getBasicReport(),
      ),
    );
    variable_set('acquia_lift_web_test_data', $test_data);
    $this
      ->resetAll();
    DummyAcquiaLiftHttpClient::clearLoggedRequests();
    AcquiaLiftAPI::setTestInstance();
    $form = $form_state = array();

    // We call the report generating function and then check the request made to the
    // Lift API.
    acquia_lift_report($form, $form_state, $agent);
    $requests = DummyAcquiaLiftHttpClient::getLoggedRequests();
    debug($requests);

    // @todo Uncomment and fix this test.

    /*    $now = time();
        $report_uri = $requests[0]['uri'];
        $parsed = parse_url($report_uri);
        $query_params = explode('&', $parsed['query']);
        $this->assertTrue(in_array('days=2', $query_params));

        // Now set the campaign to completed
        personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_COMPLETED);
        // Specify the completed time as yesterday.
        $yesterday = $now - (24 * 60 * 60);
        personalize_agent_set_stop_date($agent->machine_name, $yesterday);
        $this->resetAll();

        // Clear the logged requests.
        DummyAcquiaLiftHttpClient::clearLoggedRequests();
        // Again call the report generating function and then check the request made to the
        // Lift API. The end date should be different
        acquia_lift_report($form, $form_state, $agent);
        $requests = DummyAcquiaLiftHttpClient::getLoggedRequests();
        $confidence_report_uri = $requests[0]['uri'];
        $parsed = parse_url($confidence_report_uri);
        $query_params = explode('&', $parsed['query']);
        $this->assertTrue(in_array('days=1', $query_params));*/
  }
  public function testReportDates() {
    $this
      ->drupalLogin($this->managerUser);
    AcquiaLiftAPI::setTestInstance();
    $agents = array(
      'first-agent' => array(
        'num_options' => 2,
        'num_days' => 58,
      ),
      'second-agent' => array(
        'num_options' => 2,
        'num_days' => 70,
      ),
    );
    module_load_include('inc', 'acquia_lift', 'acquia_lift.admin');
    $now = time();
    foreach ($agents as $agent_name => &$agent_info) {
      $agent = $this
        ->createTargetingAgent($agent_name);
      $agent_name = $agent->machine_name;
      $this
        ->createOptionSet(0, array(
        'plugin' => 'some_plugin',
        'agent' => $agent_name,
        'num_options' => $agent_info['num_options'],
      ));
      personalize_goal_save($agent_name, 'user_login', 1);
      variable_set(_personalize_agent_get_status_variable($agent_name), PERSONALIZE_STATUS_RUNNING);
      $started = $now;
      $agent->started = $started - $agent_info['num_days'] * 86400;
      personalize_agent_save($agent);
      $agent_info['report_dates'] = acquia_lift_get_report_dates_for_agent($agent);
    }

    // Now check that the report dates are properly adjusted for each agent.
    // The first agent should show the complete history, i.e. 58 days.
    $this
      ->assertEqual(array(
      date('Y-m-d', $now - 58 * 86400),
      date('Y-m-d', $now),
    ), $agents['first-agent']['report_dates']);

    // The second agent has been runnign for 70 days but should only show 60.
    $this
      ->assertEqual(array(
      date('Y-m-d', $now - 60 * 86400),
      date('Y-m-d', $now),
    ), $agents['second-agent']['report_dates']);

    // Now set the max days to 90 instead of 60.
    variable_set('acquia_lift_report_max_days', 90);
    $this
      ->resetAll();
    foreach ($agents as $agent_name => &$agent_info) {
      $agent = personalize_agent_load($agent_name);
      $agent_info['report_dates'] = acquia_lift_get_report_dates_for_agent($agent);
    }

    // The first agent should still show the complete history, i.e. 58 days.
    $this
      ->assertEqual(array(
      date('Y-m-d', $now - 58 * 86400),
      date('Y-m-d', $now),
    ), $agents['first-agent']['report_dates']);

    // The second agent should now also show the complete history, i.e. 70 days.
    $this
      ->assertEqual(array(
      date('Y-m-d', $now - 70 * 86400),
      date('Y-m-d', $now),
    ), $agents['second-agent']['report_dates']);
  }
  function testWinnerLogic() {
    require_once dirname(__FILE__) . '/../includes/acquia_lift.classes.inc';
    require_once dirname(__FILE__) . '/../includes/AcquiaLiftLearnReportDataSourceInterface.inc';
    require_once dirname(__FILE__) . '/../includes/AcquiaLiftAPI.inc';
    require_once dirname(__FILE__) . '/../includes/AcquiaLiftReportDataFromFileBase.inc';
    require_once dirname(__FILE__) . '/../includes/AcquiaLiftLearnReport.inc';
    require_once dirname(__FILE__) . '/../includes/AcquiaLiftLearnReportFromFile.inc';
    require_once dirname(__FILE__) . '/acquia_lift.test_classes.inc';
    AcquiaLiftAPI::setTestInstance();
    $agent_instance = $this
      ->createTestAgent('my-test-agent', array(), self::$agent_plugin);
    $path = drupal_get_path('module', 'acquia_lift');
    $report_src = new AcquiaLiftLearnReportFromFile("/{$path}/tests/test_report_no_winner.json");
    $report = new AcquiaLiftLearnReport($agent_instance, array(
      'confidence_measure' => 95,
      'start_time' => 0,
      'end_time' => 0,
    ), $report_src);
    $this
      ->assertNull($report
      ->getOverallWinner());
    $this
      ->assertFalse($report
      ->getOverallConfidence());

    // In this report, 2 variations are beating the control, but neither is beating
    // the other.
    $report_src = new AcquiaLiftLearnReportFromFile("/{$path}/tests/test_report_no_winner_3_vars.json");
    $report = new AcquiaLiftLearnReport($agent_instance, array(
      'confidence_measure' => 95,
      'start_time' => 0,
      'end_time' => 0,
    ), $report_src);
    $this
      ->assertNull($report
      ->getOverallWinner());
    $this
      ->assertFalse($report
      ->getOverallConfidence());

    // In this report, option-b is the clear winner over option-a and option-c
    $report_src = new AcquiaLiftLearnReportFromFile("/{$path}/tests/test_report_winner_3_vars.json");
    $report = new AcquiaLiftLearnReport($agent_instance, array(
      'confidence_measure' => 95,
      'start_time' => 0,
      'end_time' => 0,
    ), $report_src);
    $this
      ->assertEqual('option-b', $report
      ->getOverallWinner());
    $this
      ->assertEqual(0.999, $report
      ->getOverallConfidence());

    // In this report the control option (option-a) is the winner over option-b
    $report_src = new AcquiaLiftLearnReportFromFile("/{$path}/tests/test_report_control_winner.json");
    $report = new AcquiaLiftLearnReport($agent_instance, array(
      'confidence_measure' => 95,
      'start_time' => 0,
      'end_time' => 0,
    ), $report_src);
    $this
      ->assertEqual('option-a', $report
      ->getOverallWinner());
    $this
      ->assertTrue(abs(0.998 - $report
      ->getOverallConfidence()) < 0.001);

    // In this report there is no winner at 95% confidence, but there is at 90%
    $report_src = new AcquiaLiftLearnReportFromFile("/{$path}/tests/test_report_winner_at_90.json");
    $report = new AcquiaLiftLearnReport($agent_instance, array(
      'confidence_measure' => 95,
      'start_time' => 0,
      'end_time' => 0,
    ), $report_src);
    $this
      ->assertNull($report
      ->getOverallWinner());
    $this
      ->assertFalse($report
      ->getOverallConfidence());
    $report_src = new AcquiaLiftLearnReportFromFile("/{$path}/tests/test_report_winner_at_90.json");
    $report = new AcquiaLiftLearnReport($agent_instance, array(
      'confidence_measure' => 90,
      'start_time' => 0,
      'end_time' => 0,
    ), $report_src);
    $this
      ->assertEqual('option-c', $report
      ->getOverallWinner());
    $this
      ->assertTrue(abs(0.9350000000000001 - $report
      ->getOverallConfidence()) < 0.001);
  }
  public function testAudienceReportLogic() {
    module_load_include('inc', 'acquia_lift', 'acquia_lift.admin');

    // First, set up our agent, option set, audience and desired targeting
    // structure.
    $agent = $this
      ->createTargetingAgent();
    $this
      ->resetAll();
    $targeting_option_set = $this
      ->createPersonalizedBlock(0, $agent, 3);

    // Keep the option ids in an array.
    $option_ids = array();
    foreach ($targeting_option_set->options as $option) {
      $option_ids[] = $option['option_id'];
    }
    $this
      ->resetAll();
    $audience_name = personalize_generate_machine_name($this
      ->randomName(), NULL, '-');
    $this
      ->createTargetAudience($targeting_option_set, $audience_name);
    $second_audience = personalize_generate_machine_name($this
      ->randomName(), NULL, '-');
    $this
      ->createTargetAudience($targeting_option_set, $second_audience, array(
      array(
        'context' => implode(PERSONALIZE_TARGETING_ADMIN_SEPARATOR, array(
          'some_plugin',
          'some_context',
        )),
        'operator' => 'equals',
        'match' => 'kthxbai',
      ),
    ));
    $targeting = array(
      $audience_name => array(
        $option_ids[2],
      ),
      $second_audience => array(
        $option_ids[0],
        $option_ids[1],
      ),
    );
    acquia_lift_save_targeting_structure($agent, $targeting);
    AcquiaLiftAPI::setTestInstance();
    acquia_lift_implement_targeting($agent);

    // Now change the structure so that we have a retired test.
    $targeting = array(
      $audience_name => array(
        $option_ids[0],
        $option_ids[2],
      ),
      $second_audience => array(
        $option_ids[1],
      ),
    );
    acquia_lift_save_targeting_structure($agent, $targeting);
    acquia_lift_implement_targeting($agent);
    $this
      ->resetAll();
    $targeting_option_set = personalize_option_set_load($targeting_option_set->osid, TRUE);
    $retired = acquia_lift_get_retired_tests($agent->machine_name);

    // So now there are 3 audiences we can view tests for: a targeting audience,
    // a running test audience, and a retired test audience.
    $retired_test = reset($retired);
    $test_audience = $audience_name . '-2';
    $targeting_audience = $second_audience . '-2';

    // Confirm the correct requests are made when we get an audience report for
    // each of these, using either old or new stats.
    AcquiaLiftAPI::setTestInstance();
    $form_state = array();
    $lift_api = AcquiaLiftAPI::getInstance(array());
    $from = $to = time();
    $from_date = $to_date = date("Y-m-d", $from);

    // Retired test - old stats.
    DummyAcquiaLiftHttpClient::clearLoggedRequests();
    acquia_lift_report_audience($form_state, $agent, $targeting_option_set, $retired_test->machine_name, $lift_api, $from, $to, TRUE, TRUE);
    $requests = DummyAcquiaLiftHttpClient::getLoggedRequests();
    $this
      ->assertEqual(1, count($requests));
    $request = reset($requests);

    // Confirm that a request was made to the old reporting end point
    $this
      ->assertTrue(strpos($request['uri'], "http://api.example.com/report?campaign_id=" . $retired_test->machine_name) === 0);

    // Retired test - new stats.
    DummyAcquiaLiftHttpClient::clearLoggedRequests();
    acquia_lift_report_audience($form_state, $agent, $targeting_option_set, $retired_test->machine_name, $lift_api, $from, $to, FALSE, TRUE);
    $requests = DummyAcquiaLiftHttpClient::getLoggedRequests();
    $this
      ->assertEqual(1, count($requests));
    $request = reset($requests);

    // Confirm the correct request is made to the new endpoint.
    $uri = "http://api.example.com/report/test?account=my-lift-web-account&site=Drupal&personalization={$agent->machine_name}&audience={$second_audience}&from={$from_date}&to={$to_date}&variation=option-1&variation=option-2&request_id=";
    $this
      ->assertTrue(strpos($request['uri'], $uri) === 0);

    // Running test - old stats
    DummyAcquiaLiftHttpClient::clearLoggedRequests();
    acquia_lift_report_audience($form_state, $agent, $targeting_option_set, $test_audience, $lift_api, $from, $to, TRUE, FALSE);
    $requests = DummyAcquiaLiftHttpClient::getLoggedRequests();
    $this
      ->assertEqual(1, count($requests));
    $request = reset($requests);
    $test_name = $agent->machine_name . "-test-2";

    // Confirm the correct request is made to the new endpoint.
    $uri = "http://api.example.com/report?campaign_id={$test_name}&from={$from_date}T00:00:00Z&days=1";
    $this
      ->assertTrue(strpos($request['uri'], $uri) === 0);

    // Running test - new stats
    DummyAcquiaLiftHttpClient::clearLoggedRequests();
    acquia_lift_report_audience($form_state, $agent, $targeting_option_set, $test_audience, $lift_api, $from, $to, FALSE, FALSE);
    $requests = DummyAcquiaLiftHttpClient::getLoggedRequests();
    $this
      ->assertEqual(1, count($requests));
    $request = reset($requests);

    // Confirm the correct request is made to the new endpoint.
    $uri = "http://api.example.com/report/test?account=my-lift-web-account&site=Drupal&personalization={$agent->machine_name}&audience={$test_audience}&from={$from_date}&to={$to_date}&variation=option-1&variation=option-3&request_id=";
    $this
      ->assertTrue(strpos($request['uri'], $uri) === 0);

    // Targeting - behavior should be the same regardless of the value of the
    // $use_old_stats var
    $uri = "http://api.example.com/report/target?account=my-lift-web-account&site=Drupal&personalization={$agent->machine_name}&audience={$targeting_audience}&from={$from_date}&to={$to_date}&variation=option-2&request_id=";
    DummyAcquiaLiftHttpClient::clearLoggedRequests();
    acquia_lift_report_audience($form_state, $agent, $targeting_option_set, $targeting_audience, $lift_api, $from, $to, TRUE, FALSE);
    $requests = DummyAcquiaLiftHttpClient::getLoggedRequests();
    $this
      ->assertEqual(1, count($requests));
    $request = reset($requests);
    $this
      ->assertTrue(strpos($request['uri'], $uri) === 0);
    DummyAcquiaLiftHttpClient::clearLoggedRequests();
    acquia_lift_report_audience($form_state, $agent, $targeting_option_set, $targeting_audience, $lift_api, $from, $to, FALSE, FALSE);
    $requests = DummyAcquiaLiftHttpClient::getLoggedRequests();
    $this
      ->assertEqual(1, count($requests));
    $request = reset($requests);
    $this
      ->assertTrue(strpos($request['uri'], $uri) === 0);
  }

}
class AcquiaLiftWebTestWorkflow extends AcquiaLiftWebTestBase {
  public static function getInfo() {
    return array(
      'name' => t('Acquia Lift Web Tests - Workflows'),
      'description' => t('Tests functionality related to particular personalization workflows.'),
      'group' => t('Personalize'),
    );
  }

  /**
   * Tests automatic creation of a goal for personalized fields and auto-
   * starting of the campaign.
   */
  public function testPersonalizeFieldsAutoCreateGoal() {
    $this
      ->resetAll();
    module_enable(array(
      'personalize_fields',
    ));
    $this
      ->resetAll();
    $admin_user = $this
      ->drupalCreateUser(array(
      'access administration pages',
      'administer site configuration',
      'access content',
      'administer content types',
      'administer nodes',
      'bypass node access',
      'manage personalized content',
    ));
    $this
      ->drupalLogin($admin_user);

    // Add personalizable field to the article node type.
    $this
      ->createPersonalizedArticleField();
    list($node1, $os1, $agent_name) = $this
      ->createPersonalizedField();
    $first_osid = 'osid-' . $os1->osid;
    $goals = personalize_goal_load_by_conditions(array(
      'agent' => $agent_name,
    ));
    $this
      ->assertEqual(1, count($goals));
    $goal = reset($goals);
    $action = visitor_actions_custom_load($goal->action);
    $this
      ->assertEqual('click', $action['event']);
    $this
      ->assertEqual('[data-personalize=osid-1]', $action['identifier']);
    $this
      ->assertEqual($os1->osid, $action['data']['auto_created']);
    $action_name = personalize_generate_machine_name(t('Clicks @option_set', array(
      '@option_set' => $os1->label,
    )), NULL, '_');
    $this
      ->assertEqual($action_name, $action['machine_name']);
    $this
      ->assertTrue($action['limited_use']);

    // Manually set the agent's status to running, bypassing the verification check.
    variable_set(_personalize_agent_get_status_variable($agent_name), PERSONALIZE_STATUS_RUNNING);
    $this
      ->resetAll();
    $expected_action_listeners = array(
      $action_name => array(
        array(
          'agent' => $agent_name,
          'value' => 1,
        ),
      ),
    );

    // Confirm that the goal is in the js settings on the /user page.
    $this
      ->drupalGet('user');
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertEqual($expected_action_listeners, $settings['personalize']['actionListeners']);

    // Change the field settings to specify particular pages for the goal.
    $edit = array(
      'field[settings][personalize][goal_pages]' => "node",
    );
    $this
      ->drupalPost('admin/structure/types/manage/article/fields/article_headline', $edit, t('Save settings'));
    $this
      ->resetAll();

    // Create another personalized field on a new node.
    list($node2, $os2, $second_agent) = $this
      ->createPersonalizedField();

    // Manually set the agent's status to running, bypassing the verification check.
    variable_set(_personalize_agent_get_status_variable($second_agent), PERSONALIZE_STATUS_RUNNING);
    $this
      ->resetAll();
    $goals = personalize_goal_load_by_conditions(array(
      'agent' => $second_agent,
    ));
    $this
      ->assertEqual(1, count($goals));
    $goal = reset($goals);

    // Confirm that the goal is *not* in the js settings on the user page but is
    // on the node page.
    $this
      ->drupalGet('user');
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertFalse(isset($settings['personalize']['actionListeners'][$goal->action]));
    $this
      ->drupalGet('node');
    $settings = $this
      ->drupalGetSettings();
    $expected_action_listeners[$goal->action] = array(
      array(
        'agent' => $second_agent,
        'value' => 1,
      ),
    );
    $this
      ->assertEqual($expected_action_listeners, $settings['personalize']['actionListeners']);

    // Now change the field settings to not auto-create a goal.
    $edit = array(
      'field[settings][personalize][create_goal]' => FALSE,
    );
    $this
      ->drupalPost('admin/structure/types/manage/article/fields/article_headline', $edit, t('Save settings'));
    list($node3, $os3, $third_agent) = $this
      ->createPersonalizedField();
    $third_osid = 'osid-' . $os3->osid;
    $this
      ->resetAll();

    // Confirm that our agent and option set were created.
    $option_set = personalize_option_set_load($os3->osid);
    $this
      ->assertEqual($third_agent, $option_set->agent);

    // There should be no goal for this agent.
    $goals = personalize_goal_load_by_conditions(array(
      'agent' => $third_agent,
    ));
    $this
      ->assertTrue(empty($goals));
  }
  public function testAutoCreateGoal() {
    $this
      ->drupalLogin($this->adminUser);
    $agent = $this
      ->createTargetingAgent();
    $option_set = $this
      ->createPersonalizedBlock(0, $agent, 2);
    $this
      ->resetAll();
    $goals = personalize_goal_load_by_conditions(array(
      'agent' => $agent->machine_name,
    ));
    $this
      ->assertEqual(1, count($goals));
    $goal = reset($goals);
    $this
      ->assertEqual('clicks_option_set_' . $option_set->osid, $goal->action);
    $this
      ->assertEqual(1, $goal->value);
    $goal_action = visitor_actions_custom_load($goal->action);
    $this
      ->assertEqual($option_set->osid, $goal_action['data']['auto_created']);

    // Delete the goal and confirm that saving the option set again does not
    // result in another goal being created.
    personalize_goal_delete($goal->id);
    personalize_option_set_save($option_set);
    $goals = personalize_goal_load_by_conditions(array(
      'agent' => $agent->machine_name,
    ), TRUE);
    $this
      ->assertEqual(0, count($goals));

    // Add an agent and create a goal before creating an option set. A second goal is
    // automatically created when creating the option set.
    $agent2 = $this
      ->createTargetingAgent();
    personalize_goal_save($agent2->machine_name, 'user_login', 2);

    // The goal should not have an auto created indicator.
    $goals = personalize_goal_load_by_conditions(array(
      'agent' => $agent2->machine_name,
    ));
    $manual_goal = reset($goals);
    $manual_goal_action = visitor_actions_custom_load($manual_goal->action);
    $this
      ->assertTrue(!isset($manual_goal_action['data']['auto_created']));
    $option_set = $this
      ->createPersonalizedBlock(1, $agent2, 2);
    $this
      ->resetAll();
    $goals = personalize_goal_load_by_conditions(array(
      'agent' => $agent2->machine_name,
    ));
    $this
      ->assertEqual(2, count($goals));
    $goal = reset($goals);
    $this
      ->assertEqual('user_login', $goal->action);
    $this
      ->assertEqual(2, $goal->value);
    $goal = end($goals);
    $goal_action = visitor_actions_custom_load($goal->action);
    $this
      ->assertEqual($option_set->osid, $goal_action['data']['auto_created']);
    $this
      ->assertEqual(1, $goal->value);

    // Now set the variable that prevents auto-creation of goals.
    variable_set('acquia_lift_auto_goal', FALSE);
    $agent3 = $this
      ->createTargetingAgent();
    $this
      ->createPersonalizedBlock(2, $agent3, 2);
    $this
      ->resetAll();
    $goals = personalize_goal_load_by_conditions(array(
      'agent' => $agent3->machine_name,
    ), TRUE);
    $this
      ->assertEqual(0, count($goals));
  }

  /**
   * Tests campaign javascript settings.
   */
  function testCampaignSettings() {
    module_enable(array(
      'personalize_test_extra_agent',
    ));
    $this
      ->resetAll();
    $this
      ->resetAll();

    // Create two agents of different types.
    $first_agent_name = $this
      ->randomName();
    $first_agent_machine_name = personalize_generate_machine_name($first_agent_name, 'personalize_agent_machine_name_exists');
    $this
      ->createTargetingAgent($first_agent_name);
    $expected = array(
      $first_agent_machine_name => array(
        'name' => $first_agent_machine_name,
        'label' => $first_agent_name,
        'type' => 'acquia_lift_target',
        'links' => array(
          'view' => url('admin/structure/personalize/manage/' . $first_agent_machine_name),
          'edit' => url('admin/structure/personalize/manage/' . $first_agent_machine_name),
          'report' => '',
          'goals' => url('admin/structure/personalize/manage/' . $first_agent_machine_name . '/goals'),
          'targeting' => url('admin/structure/personalize/manage/' . $first_agent_machine_name . '/targeting'),
          'scheduling' => url('admin/structure/personalize/manage/' . $first_agent_machine_name . '/scheduling'),
          'review' => url('admin/structure/personalize/manage/' . $first_agent_machine_name . '/review'),
        ),
        'optionSetTypes' => array(),
        'goals' => NULL,
        'editable' => TRUE,
        'status' => PERSONALIZE_STATUS_NOT_STARTED,
      ),
    );
    $admin_user = $this
      ->drupalCreateUser(array(
      'access administration pages',
      'manage personalized content',
    ));
    $this
      ->drupalLogin($admin_user);
    $this
      ->drupalGet('');
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertEqual($settings['acquia_lift']['campaigns'][$first_agent_machine_name], $expected[$first_agent_machine_name]);

    // Add a goal to the agent.
    AcquiaLiftAPI::setTestInstance();
    personalize_goal_save($first_agent_machine_name, 'user_login', 3);
    $this
      ->drupalGet('/');
    $settings = $this
      ->drupalGetSettings();
    $expected[$first_agent_machine_name]['goals'] = array(
      'user_login' => 'logs in',
    );
    $this
      ->assertEqual($settings['acquia_lift']['campaigns'][$first_agent_machine_name], $expected[$first_agent_machine_name]);
  }

}
class AcquiaLiftWebTestTarget extends AcquiaLiftWebTestBase {
  public static function getInfo() {
    return array(
      'name' => t('Acquia Lift Web Tests - Target'),
      'description' => t('Tests functionality related acquia_lift_target personalizations.'),
      'group' => t('Personalize'),
    );
  }
  public function setUp() {
    parent::setUp();
    $this
      ->configureAcquiaLiftAccount();
  }
  function testCreateTargetAudiences() {
    module_load_include('inc', 'acquia_lift', 'acquia_lift.admin');
    $agent = $this
      ->createTargetingAgent();
    $this
      ->resetAll();
    $label = $this
      ->randomName();
    $contexts = array(
      array(
        'context' => implode(PERSONALIZE_TARGETING_ADMIN_SEPARATOR, array(
          'some_plugin',
          'some_context',
        )),
        'operator' => 'contains',
        'match' => 'ohai',
      ),
      array(
        'context' => implode(PERSONALIZE_TARGETING_ADMIN_SEPARATOR, array(
          'some_plugin',
          'some_other_context',
        )),
        'operator' => 'starts',
        'match' => 'stuff',
      ),
      array(
        'context' => implode(PERSONALIZE_TARGETING_ADMIN_SEPARATOR, array(
          'some_other_plugin',
          'some_context',
        )),
        'operator' => 'equals',
        'match' => 'kthxbai',
      ),
    );

    // Try saving a target audience without having created an option set.
    $saved = acquia_lift_target_audience_save($label, $agent->machine_name, $contexts, 'AND');
    $this
      ->assertFalse($saved);

    // Now create an option set for the agent.
    $this
      ->createOptionSet(0, array(
      'plugin' => 'blocks',
      'agent' => $agent->machine_name,
      'option_ids' => array(
        'first-choice',
        'second-choice',
        'third-choice',
      ),
    ));
    $this
      ->resetAll();

    // The "everyone else" target audience should have been created.
    $option_set = acquia_lift_get_option_set_for_targeting($agent->machine_name);
    $this
      ->assertTrue(isset($option_set->targeting[ACQUIA_LIFT_TARGETING_EVERYONE_ELSE]));

    // There should not be any targeting set to the agent property yet.
    $agent = personalize_agent_load($agent->machine_name);
    $this
      ->assertFalse(isset($agent->data['lift_targeting']));

    // Add the option set options to the everyone audience.
    $targeting = array(
      ACQUIA_LIFT_TARGETING_EVERYONE_ELSE => array(
        'first-choice',
        'second-choice',
        'third-choice',
      ),
    );
    acquia_lift_save_targeting_structure($agent, $targeting);
    $agent = personalize_agent_load($agent->machine_name);
    $this
      ->assertEqual($targeting, $agent->data['lift_targeting']);
    $saved = acquia_lift_target_audience_save($label, $agent->machine_name, $contexts, 'AND');
    $this
      ->assertTrue($saved);

    // Check that the expected targeting rules were saved on the option set.
    $option_set = personalize_option_set_load($option_set->osid, TRUE);
    $this
      ->assertNotNull($option_set->targeting);
    $audience_name = personalize_generate_machine_name($label, NULL, '-');
    $expected_targeting = array(
      ACQUIA_LIFT_TARGETING_EVERYONE_ELSE => array(
        'label' => t('Everyone else'),
        'weight' => 1,
        'targeting_features' => array(),
        'targeting_rules' => array(),
        'targeting_strategy' => 'OR',
      ),
      $audience_name => array(
        'label' => $label,
        'weight' => 50,
        'targeting_features' => array(
          'some_context::sc-ohai',
          'some_other_context::ss-stuff',
          'some_context::kthxbai',
        ),
        'targeting_rules' => array(
          'some_context::sc-ohai' => array(
            'context' => 'some_context',
            'operator' => 'contains',
            'match' => 'ohai',
            'plugin' => 'some_plugin',
          ),
          'some_other_context::ss-stuff' => array(
            'context' => 'some_other_context',
            'operator' => 'starts',
            'match' => 'stuff',
            'plugin' => 'some_plugin',
          ),
          'some_context::kthxbai' => array(
            'context' => 'some_context',
            'operator' => 'equals',
            'match' => 'kthxbai',
            'plugin' => 'some_other_plugin',
          ),
        ),
        'targeting_strategy' => 'AND',
      ),
    );
    $this
      ->assertEqual($expected_targeting, $option_set->targeting);

    // Add another audience.
    $label = $this
      ->randomName();
    $contexts = array(
      array(
        'context' => implode(PERSONALIZE_TARGETING_ADMIN_SEPARATOR, array(
          'boolean_plugin',
          'some_context',
        )),
        'operator' => 'equals',
        'match' => 1,
      ),
      array(
        'context' => implode(PERSONALIZE_TARGETING_ADMIN_SEPARATOR, array(
          'boolean_plugin',
          'some_other_context',
        )),
        'operator' => 'equals',
        'match' => '0',
      ),
    );
    $this
      ->resetAll();
    $saved = acquia_lift_target_audience_save($label, $agent->machine_name, $contexts, 'OR', 60);
    $this
      ->assertTrue($saved);
    $option_set = personalize_option_set_load($option_set->osid, TRUE);
    $audience_names = array_keys($option_set->targeting);
    $expected_targeting[$audience_names[2]] = array(
      'label' => $label,
      'weight' => 60,
      'targeting_features' => array(
        'some_context::1',
        'some_other_context::0',
      ),
      'targeting_rules' => array(
        'some_context::1' => array(
          'context' => 'some_context',
          'operator' => 'equals',
          'match' => '1',
          'plugin' => 'boolean_plugin',
        ),
        'some_other_context::0' => array(
          'context' => 'some_other_context',
          'operator' => 'equals',
          'match' => '0',
          'plugin' => 'boolean_plugin',
        ),
      ),
      'targeting_strategy' => 'OR',
    );
    $this
      ->assertEqual($expected_targeting, $option_set->targeting);
  }
  function testAudienceName() {
    module_load_include('inc', 'acquia_lift', 'acquia_lift.admin');
    $agent = $this
      ->createTargetingAgent();
    $this
      ->resetAll();

    // Now create an option set for the agent.
    $this
      ->createOptionSet(0, array(
      'plugin' => 'blocks',
      'agent' => $agent->machine_name,
      'option_ids' => array(
        'first-choice',
        'second-choice',
        'third-choice',
      ),
    ));
    $this
      ->resetAll();

    // Give the audience a numeric label
    $label = 1;
    $contexts = array(
      array(
        'context' => implode(PERSONALIZE_TARGETING_ADMIN_SEPARATOR, array(
          'some_plugin',
          'some_context',
        )),
        'operator' => 'contains',
        'match' => 'ohai',
      ),
    );
    acquia_lift_target_audience_save($label, $agent->machine_name, $contexts, 'AND');
    $this
      ->resetAll();
    $option_set = acquia_lift_get_option_set_for_targeting($agent->machine_name);
    $this
      ->assertTrue(isset($option_set->targeting["audience-1"]));

    // Confirm that a pre-existing audience with a numeric name is unaffected.
    $option_set->targeting[2] = array(
      'label' => 2,
      'weight' => 49,
      'targeting_features' => array(
        0 => 'some_context::sc-ohai',
      ),
      'targeting_rules' => array(
        'some_context::sc-ohai' => array(
          'context' => 'some_context',
          'operator' => 'starts',
          'match' => 'srsly',
          'plugin' => 'some_plugin',
        ),
      ),
      'option_id' => 'second-choice',
    );
    personalize_option_set_save($option_set);
    acquia_lift_target_audience_save(2, $agent->machine_name, $contexts, 'AND', 49, 2);
    $this
      ->resetAll();
    $option_set = acquia_lift_get_option_set_for_targeting($agent->machine_name);
    $this
      ->assertFalse(isset($option_set->targeting["audience-2"]));
    $this
      ->assertTrue(isset($option_set->targeting[2]));
  }
  function testAssignVariations() {
    module_load_include('inc', 'acquia_lift', 'acquia_lift.admin');
    $agent = $this
      ->createTargetingAgent();
    $this
      ->assertFalse(isset($agent->data['lift_targeting']));
    $this
      ->resetAll();
    $option_set = $this
      ->createOptionSet(0, array(
      'plugin' => 'blocks',
      'agent' => $agent->machine_name,
      'option_ids' => array(
        'first-choice',
        'second-choice',
        'third-choice',
      ),
    ));
    $this
      ->resetAll();

    // The everyone else audience should have been created automatically.
    // Now assign the initial variations to it.
    $targeting = array(
      ACQUIA_LIFT_TARGETING_EVERYONE_ELSE => array(
        'first-choice',
        'second-choice',
        'third-choice',
      ),
    );
    acquia_lift_save_targeting_structure($agent, $targeting);
    $agent = personalize_agent_load($agent->machine_name);
    $this
      ->assertEqual($agent->data['lift_targeting'], $targeting);

    // Try to set up targeting with a non-existent audience.
    $audience_name = personalize_generate_machine_name($this
      ->randomName(), NULL, '-');
    $targeting = array(
      $audience_name => array(
        'second-choice',
        'third-choice',
      ),
      ACQUIA_LIFT_TARGETING_EVERYONE_ELSE => array(
        'first-choice',
      ),
    );
    try {
      acquia_lift_save_targeting_structure($agent, $targeting);
      $this
        ->fail('Should not reach here');
    } catch (AcquiaLiftException $e) {
      $this
        ->assertEqual('Invalid audience', $e
        ->getMessage());
    }

    // Now create the audience and try again.
    $this
      ->createTargetAudience($option_set, $audience_name);
    $this
      ->resetAll();
    try {
      acquia_lift_save_targeting_structure($agent, $targeting);
    } catch (AcquiaLiftException $e) {
      $this
        ->fail('Exception thrown when none expected.');
    }
    $this
      ->assertEqual($targeting, $agent->data['lift_targeting']);

    // Now delete the option set and re-add to add the new audience but not
    // the targeting variations.
    personalize_option_set_delete($option_set->osid);
    $agent->data['lift_targeting'] = array();
    $agent = personalize_agent_save($agent);
    $this
      ->resetAll();
    $option_set = $this
      ->createOptionSet(1, array(
      'plugin' => 'blocks',
      'agent' => $agent->machine_name,
      'option_ids' => array(
        'first-choice',
        'second-choice',
        'third-choice',
      ),
    ));

    // Verify that there is no targeting on the campaign.
    $agent = personalize_agent_load($agent->machine_name, TRUE);
    $this
      ->assertEqual($agent->data['lift_targeting'], array());

    // Verify that the everyone else audience has been added.
    $option_set = personalize_option_set_load($option_set->osid);
    $expected = array(
      ACQUIA_LIFT_TARGETING_EVERYONE_ELSE => array(
        'label' => t('Everyone'),
        'weight' => 1,
        'targeting_features' => array(),
        'targeting_rules' => array(),
        'targeting_strategy' => 'OR',
      ),
    );
    $this
      ->assertEqual($option_set->targeting, $expected);
  }
  function testImplementTargetingStructure() {
    module_load_include('inc', 'acquia_lift', 'acquia_lift.admin');

    // Take stock of the current time so we can check the lift_retired property
    // against it after retiring tests.
    $now = time();

    // First, set up our agent, option set, audience and desired targeting
    // structure.
    $agent = $this
      ->createTargetingAgent();

    // Set up some test options for nested tests.
    $agent->data['explore_rate'] = 25;
    $agent->data['control_rate'] = 25;
    $agent->data['decision_style'] = 'adaptive';
    $agent->data['cache_decisions'] = 1;
    personalize_agent_save($agent);
    $this
      ->resetAll();
    $parent_option_set = $this
      ->createPersonalizedBlock(0, $agent, 3);
    if (empty($parent_option_set)) {
      $this
        ->fail('Could not create option set');
      return;
    }

    // Keep the option ids in an array.
    $option_ids = array();
    foreach ($parent_option_set->options as $option) {
      $option_ids[] = $option['option_id'];
    }
    $this
      ->resetAll();
    $audience_name = personalize_generate_machine_name($this
      ->randomName(), NULL, '-');
    $this
      ->createTargetAudience($parent_option_set, $audience_name);
    $targeting = array(
      $audience_name => array(
        $option_ids[1],
        $option_ids[2],
      ),
    );
    try {
      acquia_lift_save_targeting_structure($agent, $targeting);
    } catch (AcquiaLiftException $e) {
      $this
        ->fail('Exception thrown when none expected.');
    }

    // Now implement the targeting structure that is currently just stored in
    // the 'lift_targeting' property.
    AcquiaLiftAPI::setTestInstance();
    acquia_lift_implement_targeting($agent);

    // We should have a new nested acquia_lift agent and option set.
    $this
      ->resetAll();
    $agents = personalize_agent_load_by_type(self::$agent_plugin);
    $this
      ->assertEqual(1, count($agents));
    $nested_agent = reset($agents);
    $nested_test_name = $nested_agent->machine_name;

    // Confirm the test options properties were set.
    $this
      ->assertEqual($nested_agent->data['decision_style'], 'adaptive');
    $this
      ->assertEqual($nested_agent->data['control_rate'], 25);
    $this
      ->assertEqual($nested_agent->data['explore_rate'], 25);
    $this
      ->assertEqual($nested_agent->data['cache_decisions'], 1);
    $option_sets = personalize_option_set_load_by_agent($nested_agent->machine_name);
    $this
      ->assertEqual(1, count($option_sets));
    $nested_osid = key($option_sets);
    $nested_option_set = reset($option_sets);
    $this
      ->assertEqual('options', $nested_option_set->plugin);

    // Confirm the correct options have been added.
    $expected_options = array(
      array(
        'option_id' => $option_ids[1],
      ),
      array(
        'option_id' => $option_ids[2],
      ),
    );
    $this
      ->assertEqual($expected_options, $nested_option_set->options);

    // Confirm this osid is on the original option set's targeting rule for that
    // audience.
    $parent_option_set = personalize_option_set_load($parent_option_set->osid, TRUE);
    $this
      ->assertEqual($nested_osid, $parent_option_set->targeting[$audience_name]['osid']);

    // Create a new target audience and change the structure of our campaign.
    $second_audience = personalize_generate_machine_name($this
      ->randomName(), NULL, '-');
    $this
      ->createTargetAudience($parent_option_set, $second_audience, array(
      array(
        'context' => implode(PERSONALIZE_TARGETING_ADMIN_SEPARATOR, array(
          'some_plugin',
          'some_context',
        )),
        'operator' => 'equals',
        'match' => 'kthxbai',
      ),
    ));
    $targeting = array(
      $audience_name => array(
        $option_ids[2],
      ),
      $second_audience => array(
        $option_ids[0],
        $option_ids[1],
      ),
    );

    // Update the test options.
    $agent->data['explore_rate'] = 35;
    $agent->data['cache_decisions'] = 0;
    personalize_agent_save($agent);
    try {
      acquia_lift_save_targeting_structure($agent, $targeting);
    } catch (AcquiaLiftException $e) {
      $this
        ->fail('Exception thrown when none expected.');
    }
    $this
      ->resetAll();

    // When we implement the new structure it should retire the existing nested
    // test and create a new one.
    AcquiaLiftAPI::setTestInstance();
    acquia_lift_implement_targeting($agent);
    $this
      ->resetAll();
    $parent_option_set = personalize_option_set_load($parent_option_set->osid, TRUE);
    $this
      ->assertFalse(isset($parent_option_set->targeting[$audience_name]['osid']));
    $this
      ->assertNotEqual($nested_osid, $parent_option_set->targeting[$second_audience]['osid']);
    $retired = acquia_lift_get_retired_tests($agent->machine_name);
    $this
      ->assertEqual(1, count($retired));

    // Load the original nested agent and confirm it has been retired.
    $retired_test = personalize_agent_load($nested_test_name, TRUE);
    $this
      ->assertTrue($retired_test->data['lift_retired'] >= $now);
    $this
      ->assertEqual($agent->machine_name, $retired_test->data['lift_parent']);
    $this
      ->assertEqual($audience_name, $retired_test->data['lift_audience']);
    $status = personalize_agent_get_status($nested_test_name);
    $this
      ->assertEqual(PERSONALIZE_STATUS_COMPLETED, $status);

    // Check the new agent and option set.
    $nested_os = personalize_option_set_load($parent_option_set->targeting[$second_audience]['osid'], TRUE);
    $nested_agent = personalize_agent_load($nested_os->agent);

    // Confirm the test options properties were set.
    $this
      ->assertEqual($nested_agent->data['decision_style'], 'adaptive');
    $this
      ->assertEqual($nested_agent->data['control_rate'], 25);
    $this
      ->assertEqual($nested_agent->data['explore_rate'], 35);
    $this
      ->assertEqual($nested_agent->data['cache_decisions'], 1);
    $option_sets = personalize_option_set_load_by_agent($nested_agent->machine_name);
    $this
      ->assertEqual(1, count($option_sets));
    $nested_osid = key($option_sets);
    $nested_option_set = reset($option_sets);
    $this
      ->assertEqual('options', $nested_option_set->plugin);

    // Confirm the correct options have been added.
    $expected_options = array(
      array(
        'option_id' => $option_ids[0],
      ),
      array(
        'option_id' => $option_ids[1],
      ),
    );
    $this
      ->assertEqual($expected_options, $nested_option_set->options);

    // Confirm this osid is on the original option set's targeting rule for that
    // audience.
    $parent_option_set = personalize_option_set_load($parent_option_set->osid, TRUE);
    $this
      ->assertEqual($nested_osid, $parent_option_set->targeting[$second_audience]['osid']);

    // This audience should not have an option id property.
    $this
      ->assertFalse(isset($parent_option_set->targeting[$second_audience]['option_id']));

    // Confirm the option_id property is now on the original audience.
    $first_audience = $audience_name . '-2';

    // Machine name will have changed.
    $this
      ->assertEqual($option_ids[2], $parent_option_set->targeting[$first_audience]['option_id']);

    // It should no longer have an osid property.
    $this
      ->assertFalse(isset($parent_option_set->targeting[$first_audience]['osid']));

    // Now let's place our personalized block so we can test how it gets rendered.
    $admin_user = $this
      ->drupalCreateUser(array(
      'access administration pages',
      'manage personalized content',
      'administer blocks',
    ));
    $this
      ->drupalLogin($admin_user);
    $edit = array(
      'blocks[personalize_blocks_' . $parent_option_set->osid . '][region]' => 'content',
    );
    $this
      ->drupalPost('admin/structure/block', $edit, t('Save blocks'));
    $this
      ->drupalLogout();
    $this
      ->drupalGet('');
    $settings = $this
      ->drupalGetSettings();

    // THe parent agent and option set should be in the personalize js settings.
    $this
      ->assertTrue(isset($settings['personalize']['agent_map'][$agent->machine_name]));
    $this
      ->assertTrue(isset($settings['personalize']['option_sets']['osid-' . $parent_option_set->osid]));

    // The nested agent and option set should *not* be in the personlaize js settings.
    $this
      ->assertFalse(isset($settings['personalize']['agent_map'][$nested_agent->machine_name]));
    $this
      ->assertFalse(isset($settings['personalize']['option_sets']['osid-' . $nested_osid]));

    // The nested agent and option set should be in the acquia_lift_target js settings.
    $this
      ->assertTrue(isset($settings['acquia_lift_target']['agent_map'][$nested_agent->machine_name]));
    $this
      ->assertTrue(isset($settings['acquia_lift_target']['option_sets']['osid-' . $nested_osid]));

    // The parent agent and option set should *not* be in the acquia_lift_target js settings.
    $this
      ->assertFalse(isset($settings['acquia_lift_target']['agent_map'][$agent->machine_name]));
    $this
      ->assertEqual(1, count($settings['acquia_lift_target']['option_sets']));

    // Change the targeting structure again to have two nested tests.
    $targeting = array(
      $first_audience => array(
        $option_ids[0],
        $option_ids[1],
      ),
      $second_audience => array(
        $option_ids[0],
        $option_ids[2],
      ),
    );

    // Update another test option too.
    $agent->data['control_rate'] = 50;
    personalize_agent_save($agent);
    try {
      acquia_lift_save_targeting_structure($agent, $targeting);
    } catch (AcquiaLiftException $e) {
      $this
        ->fail('Exception thrown when none expected.');
    }
    $this
      ->resetAll();

    // When we implement the new structure it should retire one test and create
    // two new tests.
    AcquiaLiftAPI::setTestInstance();
    acquia_lift_implement_targeting($agent);
    $this
      ->resetAll();
    $retired = acquia_lift_get_retired_tests($agent->machine_name);
    $this
      ->assertEqual(2, count($retired));

    // Both audiences' names will have changed.
    $first_audience = $first_audience . '-2';
    $second_audience = $second_audience . '-2';

    // We should have two nested agents each with one option set.
    $nested = acquia_lift_get_nested_tests($agent);
    $this
      ->assertEqual(2, count($nested));
    $nested_agents = personalize_agent_load_multiple($nested);

    // Find the osids of the new option sets so we can check they've been assigned
    // to the correct audiences.
    $new_osids = array();
    foreach ($nested_agents as $test) {

      // Verify the test options.
      // Confirm the test options properties were set.
      $this
        ->assertEqual($test->data['decision_style'], 'adaptive');
      $this
        ->assertEqual($test->data['control_rate'], 50);
      $this
        ->assertEqual($test->data['explore_rate'], 35);
      $this
        ->assertEqual($test->data['cache_decisions'], 1);
      $os = personalize_option_set_load_by_agent($test->machine_name);

      // Check the option ids to ascertain which audience the option set *should*
      // be assigned to.
      $o = reset($os);
      $ids = array_map(function ($option) {
        return $option['option_id'];
      }, $o->options);
      if (in_array('option-3', $ids)) {
        $new_osids[$second_audience] = $o->osid;
      }
      else {
        $new_osids[$first_audience] = $o->osid;
      }
    }

    // Confirm that the correct osid is assigned to each of the two target
    // audiences.
    $parent_option_set = personalize_option_set_load($parent_option_set->osid, TRUE);
    $this
      ->assertEqual(3, count($parent_option_set->targeting));
    foreach ($new_osids as $audience => $osid) {
      $this
        ->assertEqual($osid, $parent_option_set->targeting[$audience]['osid']);
      $this
        ->assertFalse(isset($parent_option_set->targeting[$audience]['option_id']));
    }
  }
  function testStopAndPickWinner() {

    // Take stock of the current time so we can check the lift_retired property
    // against it after retiring tests.
    $now = time();
    $agent = $this
      ->createTargetingAgentWithNestedTest(3);
    $this
      ->resetAll();
    $option_sets = personalize_option_set_load_by_agent($agent->machine_name);
    $option_set = reset($option_sets);
    $nested_osid = $option_set->targeting[ACQUIA_LIFT_TARGETING_EVERYONE_ELSE]['osid'];
    $nested_os = personalize_option_set_load($nested_osid);
    $nested_agent_name = $nested_os->agent;
    $expected_targeting = array(
      ACQUIA_LIFT_TARGETING_EVERYONE_ELSE => array(
        'label' => 'Everyone',
        'weight' => 1,
        'targeting_features' => array(),
        'targeting_rules' => array(),
        'targeting_strategy' => 'OR',
        'osid' => $nested_osid,
      ),
    );
    $this
      ->assertEqual($expected_targeting, $option_set->targeting);
    $this
      ->drupalLogin($this->managerUser);
    $this
      ->drupalGet('admin/structure/personalize');
    $this
      ->assertNoLinkByHref('admin/structure/personalize/manage/' . $nested_agent_name . '/delete-all');
    $this
      ->assertText('Test only');
    acquia_lift_stop_test_for_audience($agent, ACQUIA_LIFT_TARGETING_EVERYONE_ELSE, 'option-2');
    $this
      ->resetAll();
    $option_set = personalize_option_set_load($option_set->osid, TRUE);
    $expected_targeting = array(
      ACQUIA_LIFT_TARGETING_EVERYONE_ELSE => array(
        'label' => 'Everyone',
        'weight' => 1,
        'targeting_features' => array(),
        'targeting_rules' => array(),
        'targeting_strategy' => 'OR',
        'option_id' => 'option-2',
      ),
    );
    $this
      ->assertEqual($expected_targeting, $option_set->targeting);
    $retired_test = personalize_agent_load($nested_agent_name, TRUE);
    $this
      ->assertTrue($retired_test->data['lift_retired'] >= $now);
    $this
      ->assertEqual($agent->machine_name, $retired_test->data['lift_parent']);
    $this
      ->assertEqual(ACQUIA_LIFT_TARGETING_EVERYONE_ELSE, $retired_test->data['lift_audience']);
    $status = personalize_agent_get_status($nested_agent_name);
    $this
      ->assertEqual(PERSONALIZE_STATUS_COMPLETED, $status);
    $this
      ->drupalGet('admin/structure/personalize');
    $date = date('Y-m-d');
    $this
      ->assertText("(retired test) {$agent->label}: Everyone (Completed {$date})");
    $this
      ->assertLinkByHref('admin/structure/personalize/manage/' . $nested_agent_name . '/delete-all');
    $this
      ->assertNoText('Test only');

    // Now delete the retired test.
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $nested_agent_name . '/delete-all');
    $this
      ->assertText("Are you sure you want to delete the test {$agent->label}: Everyone (Completed {$date})?");
    $this
      ->drupalPost(NULL, array(), t('Delete'));

    // Confirm both the option set and test have been deleted.
    $nested_os = personalize_option_set_load($nested_osid, TRUE);
    $this
      ->assertFalse($nested_os);
    $nested_test = personalize_agent_load($nested_agent_name, TRUE);
    $this
      ->assertNull($nested_test);

    // Confirm that this has had no effect on the targeting for the parent agent.
    $option_set = personalize_option_set_load($option_set->osid, TRUE);
    $this
      ->assertEqual($expected_targeting, $option_set->targeting);

    // Create another personalization with a test and this time stop the test
    // without specifying a winner.
    $agent = $this
      ->createTargetingAgentWithNestedTest(3, 1);
    $this
      ->resetAll();
    $option_sets = personalize_option_set_load_by_agent($agent->machine_name);
    $option_set = reset($option_sets);
    $this
      ->assertTrue(isset($option_set->targeting[ACQUIA_LIFT_TARGETING_EVERYONE_ELSE]['osid']));
    $this
      ->assertFalse(isset($option_set->targeting[ACQUIA_LIFT_TARGETING_EVERYONE_ELSE]['option_id']));
    acquia_lift_stop_test_for_audience($agent, ACQUIA_LIFT_TARGETING_EVERYONE_ELSE);
    $this
      ->resetAll();
    $option_set = personalize_option_set_load($option_set->osid, TRUE);
    $this
      ->assertFalse(isset($option_set->targeting[ACQUIA_LIFT_TARGETING_EVERYONE_ELSE]['osid']));

    // The first option should now be assigned to the audience.
    $this
      ->assertEqual('option-1', $option_set->targeting[ACQUIA_LIFT_TARGETING_EVERYONE_ELSE]['option_id']);
  }
  function testNestedAgentSettings() {
    $agent = $this
      ->createTargetingAgentWithNestedTest();
    personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_RUNNING);
    $this
      ->resetAll();
    $option_sets = personalize_option_set_load_by_agent($agent->machine_name);
    $option_set = reset($option_sets);
    $this
      ->drupalGet('');
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertTrue(isset($settings['acquia_lift_target']['nested_tests']));
    $sub_agent = $agent->machine_name . '-test';
    $expected = array(
      $agent->machine_name => array(
        $sub_agent => $sub_agent,
      ),
    );
    $this
      ->assertEqual($settings['acquia_lift_target']['nested_tests'], $expected);
    $this
      ->assertEqual($settings['acquia_lift']['api_class'], 'acquiaLiftAPI');
    $this
      ->assertEqual($settings['acquia_lift_learn']['baseUrl'], 'http://api.example.com');

    // Now let's place our personalized block and confirm that the settings are
    // still as they should be.
    $admin_user = $this
      ->drupalCreateUser(array(
      'access administration pages',
      'manage personalized content',
      'administer blocks',
    ));
    $this
      ->drupalLogin($admin_user);
    $edit = array(
      'blocks[personalize_blocks_' . $option_set->osid . '][region]' => 'content',
    );
    $this
      ->drupalPost('admin/structure/block', $edit, t('Save blocks'));
    $this
      ->drupalLogout();
    $this
      ->drupalGet('');
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertTrue(isset($settings['acquia_lift_target']['nested_tests']));
    $sub_agent = $agent->machine_name . '-test';
    $expected = array(
      $agent->machine_name => array(
        $sub_agent => $sub_agent,
      ),
    );
    $this
      ->assertEqual($settings['acquia_lift_target']['nested_tests'], $expected);
    $this
      ->assertEqual($settings['acquia_lift']['api_class'], 'acquiaLiftAPI');
    $this
      ->assertEqual($settings['acquia_lift_learn']['baseUrl'], 'http://api.example.com');
  }
  function testNestedAgentAssets() {
    $agent = $this
      ->createTargetingAgentWithNestedTest();

    // Create a view event on a new page (that doesn't include any other
    // personalization).
    $node = $this
      ->drupalCreateNode();
    $action_name = $this
      ->randomName();
    $machine_name = preg_replace('/[^a-z0-9_]+/', '_', drupal_strtolower($action_name));
    $action = array(
      'plugin' => 'page',
      'label' => $action_name,
      'machine_name' => $machine_name,
      'identifier' => '',
      'event' => 'client::view',
      'pages' => 'node/' . $node->nid,
      'data' => array(),
    );
    visitor_actions_save_action($action);
    personalize_goal_save($agent->machine_name, $action_name, 1);

    // Start the campaign.
    personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_RUNNING);
    $this
      ->resetAll();

    // Load the goals page and ensure that the nested test agent assets have
    // been loaded.
    $this
      ->drupalGet('node/' . $node->nid);
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertTrue(!empty($settings['acquia_lift']));
  }
  function testNestedAgentStatus() {
    $agent_with_nesting = $this
      ->createTargetingAgentWithNestedTest();
    $this
      ->resetAll();

    // The status for each should be not started.
    $parent_status = personalize_agent_get_status($agent_with_nesting->machine_name);
    $this
      ->assertEqual(PERSONALIZE_STATUS_NOT_STARTED, $parent_status);
    $nested = acquia_lift_get_nested_tests($agent_with_nesting);
    $nested_agent_name = reset($nested);
    $child_status = personalize_agent_get_status($nested_agent_name);
    $this
      ->assertEqual(PERSONALIZE_STATUS_NOT_STARTED, $child_status);

    // Setting the status of the parent should result in the same status being
    // set on the child.
    personalize_agent_set_status($agent_with_nesting->machine_name, PERSONALIZE_STATUS_RUNNING);
    $this
      ->resetAll();
    $parent_status = personalize_agent_get_status($agent_with_nesting->machine_name);
    $this
      ->assertEqual(PERSONALIZE_STATUS_RUNNING, $parent_status);
    $child_status = personalize_agent_get_status($nested_agent_name);
    $this
      ->assertEqual(PERSONALIZE_STATUS_RUNNING, $child_status);
  }
  function testNestedAgentDeletion() {
    $agent_with_nesting = $this
      ->createTargetingAgentWithNestedTest(2);

    // Add another option set and make it lock-step.
    $agent_with_nesting->data['variation_set_handling'] = ACQUIA_LIFT_DECISION_LOCKSTEP;
    $second_os = $this
      ->createOptionSet(1, array(
      'agent' => $agent_with_nesting->machine_name,
      'plugin' => 'some_plugin',
      'num_options' => 2,
    ));
    AcquiaLiftAPI::setTestInstance();
    acquia_lift_implement_targeting($agent_with_nesting);
    $this
      ->resetAll();

    // Confirm the nested test has been created as expected.
    $nested_tests = acquia_lift_get_nested_tests($agent_with_nesting);
    $nested_agent_name = reset($nested_tests);
    $nested_agent = personalize_agent_load($nested_agent_name, TRUE);
    $this
      ->assertNotNull($nested_agent);
    $nested_os = personalize_option_set_load_by_agent($nested_agent_name);
    $this
      ->assertEqual(1, count($nested_os));
    $nested_os = reset($nested_os);
    $this
      ->assertNotNull($nested_os);
    DummyAcquiaLiftHttpClient::clearLoggedRequests();
    AcquiaLiftAPI::setTestInstance();
    personalize_option_set_delete($second_os->osid);
    $this
      ->resetAll();
    $requests = DummyAcquiaLiftHttpClient::getLoggedRequests();
    $this
      ->assertEqual(array(), $requests);

    // Confirm the agent still exists.
    $nested_agent = personalize_agent_load($nested_agent_name, TRUE);
    $this
      ->assertNotNull($nested_agent);

    // Now delete the remaining option set.
    $option_set = acquia_lift_get_option_set_for_targeting($agent_with_nesting->machine_name);
    personalize_option_set_delete($option_set->osid);
    $this
      ->resetAll();
    $requests = DummyAcquiaLiftHttpClient::getLoggedRequests();
    $this
      ->assertEqual('delete', $requests[0]['type']);
    $pattern = preg_quote("http://api.example.com/campaigns/{$nested_agent_name}?request_id=", '#') . '[a-zA-Z0-9-_]*' . preg_quote('&client_id=test-api-key', '#');
    $this
      ->assertTrue(preg_match("#{$pattern}#", $requests[0]['uri']));
    $nested_agent = personalize_agent_load($nested_agent_name, TRUE);
    $this
      ->assertNull($nested_agent);
    $nested_os = personalize_option_set_load_by_agent($nested_agent_name, TRUE);
    $this
      ->assertEqual(0, count($nested_os));
  }

  /**
   * Tests which components of a campaign are editable when the depending on
   * agent status.
   */
  function testAgentEditable() {
    $this
      ->drupalLogin($this->managerUser);
    $agent = $this
      ->createTargetingAgent();
    $option_set = $this
      ->createOptionSet(0, array(
      'plugin' => 'blocks',
      'agent' => $agent->machine_name,
      'option_ids' => array(
        'first-choice',
        'second-choice',
        'third-choice',
      ),
    ));
    $this
      ->resetAll();

    // Load the automatic goal for reference.
    $goals = personalize_goal_load_by_conditions(array(
      'agent' => $agent->machine_name,
    ));
    $this
      ->assertEqual(count($goals), 1);
    $goal = reset($goals);

    // Verify that the agent is shown for administration.
    $this
      ->drupalGet('');
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertTrue(!empty($settings['acquia_lift']['campaigns'][$agent->machine_name]));

    // Start the agent through the UI so that the targeting gets implemented.
    $this
      ->createTestFromOptionSet($agent, $option_set);
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/review');
    $this
      ->drupalPost(NULL, array(), $this
      ->getButton('wizard_start'));

    // Verify that the agent is no longer shown for administration.
    $this
      ->drupalGet('');
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertFalse($settings['acquia_lift']['campaigns'][$agent->machine_name]['editable']);

    // Try to edit the goal.
    try {
      personalize_goal_save($agent->machine_name, 'clicks_option_set_1', 5, $goal->id);
      $this
        ->fail('Should not ever get here because a cannot be saved when agent is running.');
    } catch (Exception $e) {
      $this
        ->assertTrue($e instanceof PersonalizeException);
      $this
        ->assertEqual($e
        ->getMessage(), 'Goals cannot be modified until the personalization is paused.');
    }

    // Try to add a variation
    $option_set->options[] = array(
      'option_id' => 'fourth-choice',
      'option_label' => 'Fourth choice',
    );
    try {
      $option_set = personalize_option_set_save($option_set);
      $this
        ->pass('No errors should be thrown when adding variations to a running campaign.');
    } catch (Exception $e) {
      $this
        ->fail('No errors should be thrown when adding variations to a running campaign.');
    }

    // Try to delete the new variation.
    array_pop($option_set->options);
    try {
      $option_set = personalize_option_set_save($option_set);
      $this
        ->pass('No errors should be thrown when deleting non-targeted variations from a running campaign.');
    } catch (Exception $e) {
      $this
        ->fail('No errors should be thrown when deleting non-targeted variations from a running campaign.');
    }

    // Try to delete a targeted option.
    unset($option_set->options[0]);
    try {
      $option_set = personalize_option_set_save($option_set);
      $this
        ->fail('Should not get here because an error should be thrown while removing this variation.');
    } catch (Exception $e) {
      $this
        ->assertTrue($e instanceof PersonalizeException);
      $this
        ->assertEqual($e
        ->getMessage(), 'Variations used in targeting cannot be removed until the personalization is paused.');
    }

    // Pause the agent.
    personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_PAUSED);

    // Edit the goal.
    personalize_goal_save($agent->machine_name, 'clicks_option_set_1', 5, $goal->id);

    // Verify the change.
    $goal = personalize_goal_load($goal->id);
    $this
      ->assertEqual($goal->value, 5);

    // Remove the variation.
    $option_set = personalize_option_set_save($option_set);
    $this
      ->assertEqual(count($option_set->options), 2);

    // Verify the settings for administration.
    $this
      ->drupalGet('');
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertTrue($settings['acquia_lift']['campaigns'][$agent->machine_name]['editable']);

    // Schedule the agent.
    $start_date = strtotime('+1 month midnight');
    personalize_agent_set_start_date($agent->machine_name, $start_date);
    personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_SCHEDULED);

    // Try to edit the goal.
    try {
      personalize_goal_save($agent->machine_name, 'clicks_option_set_1', 3, $goal->id);
      $this
        ->fail('Should not ever get here because a cannot be saved when agent is running.');
    } catch (Exception $e) {
      $this
        ->assertTrue($e instanceof PersonalizeException);
      $this
        ->assertEqual($e
        ->getMessage(), 'Goals cannot be modified until the personalization is paused.');
    }

    // Try to delete a targeted option.
    unset($option_set->options[1]);
    try {
      $option_set = personalize_option_set_save($option_set);
      $this
        ->fail('Should not get here because an error should be thrown while removing this variation.');
    } catch (Exception $e) {
      $this
        ->assertTrue($e instanceof PersonalizeException);
      $this
        ->assertEqual($e
        ->getMessage(), 'Variations used in targeting cannot be removed until the personalization is paused.');
    }

    // Verify the agent can't be edited in JS settings.
    $this
      ->drupalGet('');
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertFalse($settings['acquia_lift']['campaigns'][$agent->machine_name]['editable']);

    // Complete the agent.
    personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_COMPLETED);

    // Try to edit the goal.
    try {
      personalize_goal_save($agent->machine_name, 'clicks_option_set_1', 10, $goal->id);
      $this
        ->fail('Should not ever get here because a cannot be saved when agent is running.');
    } catch (Exception $e) {
      $this
        ->assertTrue($e instanceof PersonalizeException);
      $this
        ->assertEqual($e
        ->getMessage(), 'Goals cannot be modified until the personalization is paused.');
    }

    // Verify the agent still isn't loaded for front-end administration.
    $this
      ->drupalGet('');
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertTrue(empty($settings['acquia_lift']['campaigns'][$agent->machine_name]));
  }

  /**
   * Tests messaging for available operations based on agent status.
   */
  public function testAgentEditableMessaging() {
    module_enable(array(
      'personalize_blocks',
      'personalize_elements',
      'personalize_fields',
    ));
    $this
      ->resetAll();
    $admin_user = $this
      ->drupalCreateUser(array(
      'access administration pages',
      'administer site configuration',
      'access content',
      'administer content types',
      'administer nodes',
      'bypass node access',
      'manage personalized content',
    ));
    $this
      ->drupalLogin($admin_user);

    // Set the test classes for working with option set manipulation.
    AcquiaLiftAPI::setTestInstance();
    $agent = $this
      ->createTargetingAgent();

    // Personalize blocks.
    $option_set = $this
      ->createPersonalizedBlock(1, $agent, 2);

    // Add targeting so that the agent meets requirements.
    $this
      ->createTestFromOptionSet($agent, $option_set);
    $pb_message = 'Variations in use cannot be removed from Personalized Block 2 until the ' . $agent->label . ' personalization is paused.';
    $this
      ->drupalGet('admin/structure/personalize/variations/personalize-blocks/manage/1/edit');
    $this
      ->assertNoText($pb_message);

    // Start the agent via the UI in order to implement targeting and nested agents.
    $this
      ->drupalPost('admin/structure/personalize/manage/' . $agent->machine_name . '/review', array(), $this
      ->getButton('wizard_start'));
    $this
      ->drupalGet('admin/structure/personalize/variations/personalize-blocks/manage/1/edit');
    $this
      ->assertText($pb_message);

    // Reset the agent.
    personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_NOT_STARTED);
    personalize_option_set_delete($option_set->osid);

    // Personalize elements.
    $option_set = $this
      ->createPersonalizeElementsOptionSet($agent->machine_name, array(
      'num_options' => 4,
    ));
    $pe_message = 'Variations that are in use cannot be removed until the ' . $agent->label . ' personalization is paused.';
    $this
      ->drupalGet('admin/structure/personalize/variations/personalize-elements/manage/' . $option_set->osid . '/edit');
    $this
      ->assertNoText($pe_message);
    $edit = array(
      'options[1][personalize_elements_content]' => 'Mahna mahna',
      'options[2][personalize_elements_content]' => 'Do doo do do do',
      'options[3][personalize_elements_content]' => 'Mahna mahna',
      'options[4][personalize_elements_content]' => '',
    );
    $this
      ->drupalPost(NULL, $edit, 'Save');
    $this
      ->resetAll();

    // Verify that one option was removed.
    $option_set = personalize_option_set_load($option_set->osid);
    $this
      ->assertEqual(count($option_set->options), 3);
    $this
      ->createTestFromOptionSet($agent, $option_set);

    // Start the agent via the UI in order to implement targeting and nested agents.
    $this
      ->drupalPost('admin/structure/personalize/manage/' . $agent->machine_name . '/review', array(), $this
      ->getButton('wizard_start'));
    $this
      ->drupalGet('admin/structure/personalize/variations/personalize-elements/manage/' . $option_set->osid . '/edit');
    $this
      ->assertText($pe_message);
    $edit = array(
      'options[1][personalize_elements_content]' => 'Mahna mahna',
      'options[2][personalize_elements_content]' => 'Do doo do do do',
      'options[3][personalize_elements_content]' => '',
    );
    $this
      ->drupalPost(NULL, $edit, 'Save');
    $this
      ->resetAll();
    $this
      ->assertText('Variations cannot be removed until the ' . $agent->label . ' personalization is paused.');
    $option_set = personalize_option_set_load($option_set->osid);
    $this
      ->assertEqual(count($option_set->options), 3);

    // Personalize fields.
    $this
      ->createPersonalizedArticleField();
    list($node, $os, $agent_name) = $this
      ->createPersonalizedField();

    // Start the agent via the UI in order to implement targeting and nested agents.
    $field_agent = personalize_agent_load($agent_name);
    $this
      ->createTestFromOptionSet($field_agent, $os);
    $this
      ->drupalPost('admin/structure/personalize/manage/' . $agent_name . '/review', array(), $this
      ->getButton('wizard_start'));

    // Verify you can't remove from a running agent.
    $pf_message = 'The Personalizable Headline field cannot be removed until the personalization is paused.';
    $this
      ->drupalGet('node/1/edit');
    $edit = array(
      'article_headline[und][0][value]' => '',
    );
    $this
      ->drupalPost(NULL, $edit, 'Save');
    $this
      ->assertText($pf_message);
    personalize_agent_set_status($agent_name, PERSONALIZE_STATUS_PAUSED);
    $this
      ->drupalGet('node/1/edit');
    $edit = array(
      'article_headline[und][0][value]' => '',
    );
    $this
      ->drupalPost(NULL, $edit, 'Save');
    $this
      ->assertNoText($pf_message);
  }
  function testMultipleOptionSetsOneDecision() {
    $this
      ->drupalLogin($this->managerUser);
    $targeting_agent = $this
      ->createTargetingAgent();

    // Add a couple of option sets with different numbers of options.
    $os1 = $this
      ->createOptionSet(1, array(
      'agent' => $targeting_agent->machine_name,
      'plugin' => 'type1',
      'num_options' => 2,
    ));
    $os2 = $this
      ->createOptionSet(2, array(
      'agent' => $targeting_agent->machine_name,
      'plugin' => 'type1',
      'num_options' => 3,
    ));
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $targeting_agent->machine_name . '/review');
    $this
      ->assertText('You have multiple variation sets with different numbers of variations.');

    // Add a third variation to the first option set.
    $os1->options[] = array(
      'option_id' => 'option-ohai',
    );
    personalize_option_set_save($os1);
    $this
      ->resetAll();
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $targeting_agent->machine_name . '/review');
    $this
      ->assertNoText('You have multiple variation sets with different numbers of variations.');

    // Right now the option IDs will not be the same - at least the third one
    // will be different.
    $this
      ->assertFalse($os1->options[2]['option_id'] == $os2->options[2]['option_id']);

    // Now implement the structure. The option IDs on all option sets should be
    // updated to match those of the targeting option set.
    AcquiaLiftAPI::setTestInstance();

    // Implement the targeting as a basic test.
    $targeting_agent->data['lift_targeting'] = array(
      ACQUIA_LIFT_TARGETING_EVERYONE_ELSE => array(
        $os1->options[0]['option_id'],
        $os1->options[1]['option_id'],
        $os1->options[2]['option_id'],
      ),
    );
    acquia_lift_implement_targeting($targeting_agent);
    $this
      ->resetAll();

    // Refresh the option sets.
    $os1 = personalize_option_set_load($os1->osid, TRUE);
    $os2 = personalize_option_set_load($os2->osid, TRUE);
    $option_ids = array();
    foreach (array(
      $os1->osid => $os1,
      $os2->osid => $os2,
    ) as $osid => $os) {
      $option_ids[$osid] = array();
      foreach ($os->options as $option) {
        $option_ids[$osid][] = $option['option_id'];
      }
    }
    $this
      ->assertEqual($option_ids[$os1->osid], $option_ids[$os2->osid]);
  }
  function testMVTCreation() {
    $this
      ->drupalLogin($this->managerUser);
    $targeting_agent = $this
      ->createTargetingAgent();
    $targeting_agent->data['variation_set_handling'] = ACQUIA_LIFT_DECISION_MULTIVARIATE;
    personalize_agent_save($targeting_agent);

    // Add a single option set, should not get past the review screen.
    $os1 = $this
      ->createOptionSet(1, array(
      'agent' => $targeting_agent->machine_name,
      'plugin' => 'type1',
      'num_options' => 2,
    ));

    // Add a couple of goals.
    personalize_goal_save($targeting_agent->machine_name, 'form_submit', 1);
    personalize_goal_save($targeting_agent->machine_name, 'user_login', 2);

    // Verify the error message.
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $targeting_agent->machine_name . '/review');
    $this
      ->assertText('A multi-variate test requires at least two option sets.');
    $this
      ->assertNoText('You have multiple variation sets with different numbers of variations - the personalization cannot be started until all variation sets have the same number of variations.');

    // Add another option set.
    $os2 = $this
      ->createOptionSet(2, array(
      'agent' => $targeting_agent->machine_name,
      'plugin' => 'type1',
      'num_options' => 3,
    ));
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $targeting_agent->machine_name . '/review');
    $this
      ->assertNoText('A multi-variate test requires at least two option sets.');
    $this
      ->assertNoText('You have multiple variation sets with different numbers of variations - the personalization cannot be started until all variation sets have the same number of variations.');

    // Grab the goals created so we can assert that they get moved over to the
    // MVT later.
    $goals = personalize_goal_load_by_conditions(array(
      'agent' => $targeting_agent->machine_name,
    ), TRUE);

    // Just pull the details out into an array.
    $original_goal_info = array();
    foreach ($goals as $goal) {
      $goal_array = (array) $goal;
      unset($goal_array['agent']);
      $original_goal_info[$goal->id] = $goal_array;
    }

    // Implement the MVT.
    AcquiaLiftAPI::setTestInstance();
    acquia_lift_implement_mvt($targeting_agent);
    $this
      ->resetAll();
    $nested = personalize_agent_load_by_type(ACQUIA_LIFT_TESTING_AGENT, TRUE);
    $nested_mvt = reset($nested);
    $this
      ->assertEqual($nested_mvt->machine_name, acquia_lift_get_mvt_name_for_agent($targeting_agent->machine_name));
    $option_sets = personalize_option_set_load_by_agent($nested_mvt->machine_name, TRUE);
    $this
      ->assertTrue(isset($option_sets[$os1->osid]));
    $this
      ->assertTrue(isset($option_sets[$os2->osid]));
    $goals = personalize_goal_load_by_conditions(array(
      'agent' => $nested_mvt->machine_name,
    ), TRUE);
    $mvt_goal_info = array();
    foreach ($goals as $goal) {
      $goal_array = (array) $goal;
      unset($goal_array['agent']);
      $mvt_goal_info[$goal->id] = $goal_array;
    }
    $this
      ->assertEqual($original_goal_info, $mvt_goal_info);

    // There shouldn't be any option sets or goals on the parent agent.
    $option_sets_original = personalize_option_set_load_by_agent($targeting_agent->machine_name, TRUE);
    $this
      ->assertTrue(empty($option_sets_original));
    $goals_original = personalize_goal_load_by_conditions(array(
      'agent' => $targeting_agent->machine_name,
    ), TRUE);
    $this
      ->assertTrue(empty($goals_original));
  }
  function testLockstepVariations() {
    $this
      ->drupalLogin($this->managerUser);
    $targeting_agent = $this
      ->createTargetingAgent();

    // Add a couple of option sets with different numbers of options.
    $os1 = $this
      ->createOptionSet(1, array(
      'agent' => $targeting_agent->machine_name,
      'plugin' => 'type1',
      'num_options' => 3,
    ));
    $os2 = $this
      ->createOptionSet(2, array(
      'agent' => $targeting_agent->machine_name,
      'plugin' => 'type1',
      'num_options' => 3,
    ));
    $elements_os = $this
      ->createPersonalizeElementsOptionSet($targeting_agent->machine_name, array(
      'add_control' => TRUE,
      'num_options' => 2,
    ));
    $targeting_option_set = acquia_lift_get_option_set_for_targeting($targeting_agent->machine_name);
    $this
      ->assertEqual($elements_os->osid, $targeting_option_set->osid);
    $option_ids = array();
    foreach ($targeting_option_set->options as $option) {
      $option_ids[] = $option['option_id'];
    }

    // Now implement the structure. The option IDs on all option sets should be
    // updated to match those of the targeting option set.
    AcquiaLiftAPI::setTestInstance();
    $targeting = array(
      ACQUIA_LIFT_TARGETING_EVERYONE_ELSE => $option_ids,
    );
    try {
      acquia_lift_save_targeting_structure($targeting_agent, $targeting);
    } catch (AcquiaLiftException $e) {
      $this
        ->fail('Exception thrown when none expected.');
    }

    // Implement the targeting as a basic test.
    acquia_lift_implement_targeting($targeting_agent);
    $this
      ->resetAll();
    $this
      ->drupalGet('');
    $settings = $this
      ->drupalGetSettings();
    $option_set_settings = $settings['personalize']['option_sets'];

    // Confirm that the control variation has the correct option id.
    $this
      ->assertEqual(PERSONALIZE_CONTROL_OPTION_ID, $option_set_settings['osid-' . $elements_os->osid]['options'][0]['option_id']);
  }
  function testAudienceChanges() {
    module_load_include('inc', 'acquia_lift', 'acquia_lift.admin');

    // First, set up our agent, option set, audience and desired targeting
    // structure.
    $agent = $this
      ->createTargetingAgent();
    $parent_option_set = $this
      ->createPersonalizedBlock(0, $agent, 3);

    // Keep the option ids in an array.
    $option_ids = array();
    foreach ($parent_option_set->options as $option) {
      $option_ids[] = $option['option_id'];
    }
    $this
      ->resetAll();
    $first_audience = personalize_generate_machine_name($this
      ->randomName(), NULL, '-');
    $this
      ->createTargetAudience($parent_option_set, $first_audience);
    $second_audience = personalize_generate_machine_name($this
      ->randomName(), NULL, '-');
    $this
      ->createTargetAudience($parent_option_set, $second_audience);
    $targeting = array(
      $first_audience => array(
        $option_ids[1],
        $option_ids[2],
      ),
      $second_audience => array(
        $option_ids[0],
      ),
    );
    acquia_lift_save_targeting_structure($agent, $targeting);

    // Now implement the targeting structure..
    AcquiaLiftAPI::setTestInstance();
    acquia_lift_implement_targeting($agent);
    $this
      ->resetAll();
    $os = acquia_lift_get_option_set_for_targeting($agent->machine_name);

    // There should be three audiences - the two we created plus the "everyone"
    // audience.
    $this
      ->assertEqual(3, count(array_keys($os->targeting)));

    // The first audience should have an osid but no option_id
    $this
      ->assertTrue(isset($os->targeting[$first_audience]));
    $this
      ->assertTrue(isset($os->targeting[$first_audience]['osid']));
    $this
      ->assertFalse(isset($os->targeting[$first_audience]['option_id']));

    // The second audience should have an option_id but no osid
    $this
      ->assertTrue(isset($os->targeting[$second_audience]));
    $this
      ->assertFalse(isset($os->targeting[$second_audience]['osid']));
    $this
      ->assertTrue(isset($os->targeting[$second_audience]['option_id']));

    // Now change the structure so that that the first audience no longer gets a
    // test and the second one gets a test.
    $targeting2 = array(
      $first_audience => array(
        $option_ids[0],
      ),
      $second_audience => array(
        $option_ids[1],
        $option_ids[2],
      ),
    );
    acquia_lift_save_targeting_structure($agent, $targeting2);
    AcquiaLiftAPI::setTestInstance();
    acquia_lift_implement_targeting($agent);
    $this
      ->resetAll();
    $os = acquia_lift_get_option_set_for_targeting($agent->machine_name);
    $this
      ->assertEqual(3, count(array_keys($os->targeting)));

    // The first audience's name should have been changed.
    $this
      ->assertFalse(isset($os->targeting[$first_audience]));
    $new_first_audience = $first_audience . '-2';

    // The new first audience should now have an option_id but no osid.
    $this
      ->assertTrue(isset($os->targeting[$new_first_audience]));
    $this
      ->assertFalse(isset($os->targeting[$new_first_audience]['osid']));
    $this
      ->assertTrue(isset($os->targeting[$new_first_audience]['option_id']));
    $this
      ->assertEqual('option-1', $os->targeting[$new_first_audience]['option_id']);

    // The second audience's name should also have been changed.
    $this
      ->assertFalse(isset($os->targeting[$second_audience]));
    $new_second_audience = $second_audience . '-2';

    // The second audience should have an option_id but no osid
    $this
      ->assertTrue(isset($os->targeting[$new_second_audience]));
    $this
      ->assertTrue(isset($os->targeting[$new_second_audience]['osid']));
    $this
      ->assertFalse(isset($os->targeting[$new_second_audience]['option_id']));

    // The original test that existed for the first audience should now exist
    // as a retired test.
    $retired = acquia_lift_get_retired_tests($agent->machine_name);
    $this
      ->assertEqual(1, count($retired));
    $this
      ->assertEqual($first_audience, $retired[0]->data['lift_audience']);

    // Now change the first audience to get a different fixed targeting option.
    // The audience name should stay the same.
    $targeting3 = array(
      $new_first_audience => array(
        $option_ids[1],
      ),
      $new_second_audience => array(
        $option_ids[1],
        $option_ids[2],
      ),
    );
    acquia_lift_save_targeting_structure($agent, $targeting3);
    AcquiaLiftAPI::setTestInstance();
    acquia_lift_implement_targeting($agent);
    $this
      ->resetAll();
    $os = acquia_lift_get_option_set_for_targeting($agent->machine_name);
    $this
      ->assertEqual(3, count(array_keys($os->targeting)));

    // The new first audience should now have an option_id but no osid.
    $this
      ->assertTrue(isset($os->targeting[$new_first_audience]));
    $this
      ->assertFalse(isset($os->targeting[$new_first_audience]['osid']));
    $this
      ->assertTrue(isset($os->targeting[$new_first_audience]['option_id']));
    $this
      ->assertEqual('option-2', $os->targeting[$new_first_audience]['option_id']);

    // The second audience should be the same as before.
    $this
      ->assertTrue(isset($os->targeting[$new_second_audience]));
    $this
      ->assertTrue(isset($os->targeting[$new_second_audience]['osid']));
    $this
      ->assertFalse(isset($os->targeting[$new_second_audience]['option_id']));
  }

}

/**
 * Base class for all campaign wizard tests.
 *
 * Class AcquiaLiftWebTestCampaignWizardBase
 */
class AcquiaLiftWebTestCampaignWizardBase extends AcquiaLiftWebTestBase {
  protected $addVariationSetElement;
  protected $changeTypeElement;
  protected $addTargetAudienceElement;
  protected $addGoalElement;
  public function setUp() {
    parent::setUp();
    $this
      ->configureAcquiaLiftAccount();
    $this
      ->drupalLogin($this->managerUser);
    $this->addVariationSetElement = array(
      'op' => t('Add variation set'),
    );
    $this->changeTypeElement = array(
      'op' => t('Change type'),
    );
    $this->addTargetAudienceElement = array(
      'op' => t('Add target audience'),
    );
    $this->addGoalElement = array(
      'op' => t('Add goal'),
    );
  }

}
class AcquiaLiftWebTestCampaignWizardVariations extends AcquiaLiftWebTestCampaignWizardBase {
  public static function getInfo() {
    return array(
      'name' => t('Acquia Lift Web Tests - Personalization Wizard Variations'),
      'description' => t('Tests functionality related to the personalization management wizard variation sets.'),
      'group' => t('Personalize'),
    );
  }
  function testVariationTypeSelect() {
    $variation_input_name = key($this->addVariationSetElement);
    $variation_input_value = reset($this->addVariationSetElement);
    $block_title_name = 'variations[editing][new][0][block][content][title]';
    $element_url_name = 'variations[editing][new][0][element][content][url]';
    $option_set_type_name = 'variations[editing][new][0][option_set_type]';
    $block_type_id = 'edit-variations-editing-new-0-option-set-type-block';
    $element_type_id = 'edit-variations-editing-new-0-option-set-type-element';
    $this
      ->drupalLogin($this->managerUser);
    $agent = $this
      ->createTargetingAgent();
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
    $this
      ->drupalPostAJAX(NULL, array(), $this->addVariationSetElement);

    // Make sure the type selection is shown by default without any selections.
    $this
      ->assertFieldByName($option_set_type_name);
    $this
      ->assertNoFieldChecked($block_type_id);
    $this
      ->assertNoFieldChecked($element_type_id);

    // Actual forms should not be shown yet.
    $this
      ->assertNoFieldByName($block_title_name);
    $this
      ->assertNoFieldByName($element_url_name);

    // Button to add a new variation set should still be available.
    $this
      ->assertFieldByName($variation_input_name, $variation_input_value);

    // Cancel variation set creation.
    $this
      ->drupalPostAJAX(NULL, array(), array(
      'cancel_option_set_0' => t('Cancel'),
    ));
    $this
      ->assertFieldByName($variation_input_name, $variation_input_value);
    $this
      ->assertNoFieldByName($option_set_type_name);
    $this
      ->assertNoFieldByName($block_title_name);
    $this
      ->assertNoFieldByName($element_url_name);

    // Select a block variation set.
    $this
      ->drupalPostAJAX(NULL, array(), $this->addVariationSetElement);
    $this
      ->assertFieldByName($option_set_type_name);
    $this
      ->assertNoFieldChecked($block_type_id);
    $this
      ->assertNoFieldChecked($element_type_id);
    $this
      ->assertNoFieldByName($block_title_name);
    $this
      ->assertNoFieldByName($element_url_name);
    $this
      ->assertFieldByName($variation_input_name, $variation_input_value);
    $edit = array(
      $option_set_type_name => 'block',
    );
    $this
      ->drupalPostAJAX(NULL, $edit, $option_set_type_name);
    $this
      ->assertFieldByName($variation_input_name, $variation_input_value);
    $this
      ->assertNoFieldByName($option_set_type_name);
    $this
      ->assertFieldByName($block_title_name);
    $this
      ->assertNoFieldByName($element_url_name);

    // Change the type
    $this
      ->drupalPostAJAX(NULL, array(), $this->changeTypeElement);
    $this
      ->assertFieldByName($option_set_type_name);
    $this
      ->assertNoFieldChecked($block_type_id);
    $this
      ->assertNoFieldChecked($element_type_id);
    $this
      ->assertNoFieldByName($block_title_name);
    $this
      ->assertNoFieldByName($element_url_name);
    $this
      ->assertFieldByName($variation_input_name, $variation_input_value);

    // Select block again.
    $edit = array(
      $option_set_type_name => 'block',
    );
    $this
      ->drupalPostAJAX(NULL, $edit, $option_set_type_name);
    $this
      ->assertFieldByName($variation_input_name, $variation_input_value);
    $this
      ->assertNoFieldByName($option_set_type_name);
    $this
      ->assertFieldByName($block_title_name);
    $this
      ->assertNoFieldByName($element_url_name);

    // Cancel the creation of the variation set.
    $this
      ->drupalPostAJAX(NULL, array(), array(
      'cancel_block_option_set_0' => t('Cancel'),
    ));
    $this
      ->assertFieldByname($variation_input_name, $variation_input_value);
    $this
      ->assertNoFieldByName($option_set_type_name);
    $this
      ->assertNoFieldByName($block_title_name);
    $this
      ->assertNoFieldByName($element_url_name);

    // Select an element variation set.
    $this
      ->drupalPostAJAX(NULL, array(), $this->addVariationSetElement);
    $this
      ->assertFieldByName($option_set_type_name);
    $this
      ->assertNoFieldChecked($block_type_id);
    $this
      ->assertNoFieldChecked($element_type_id);
    $this
      ->assertNoFieldByName($block_title_name);
    $this
      ->assertNoFieldByName($element_url_name);
    $this
      ->assertFieldByName($variation_input_name, $variation_input_value);
    $edit = array(
      $option_set_type_name => 'element',
    );
    $this
      ->drupalPostAJAX(NULL, $edit, $option_set_type_name);
    $this
      ->assertFieldByName($variation_input_name, $variation_input_value);
    $this
      ->assertNoFieldByName($option_set_type_name);
    $this
      ->assertNoFieldByName($block_title_name);
    $this
      ->assertFieldByName($element_url_name);

    // Change the type.
    $this
      ->drupalPostAJAX(NULL, array(), $this->changeTypeElement);
    $this
      ->assertFieldByName($option_set_type_name);
    $this
      ->assertNoFieldChecked($block_type_id);
    $this
      ->assertNoFieldChecked($element_type_id);
    $this
      ->assertNoFieldByName($block_title_name);
    $this
      ->assertNoFieldByName($element_url_name);
    $this
      ->assertFieldByName($variation_input_name, $variation_input_value);

    // Select element again.
    $edit = array(
      $option_set_type_name => 'element',
    );
    $this
      ->drupalPostAJAX(NULL, $edit, $option_set_type_name);
    $this
      ->assertFieldByName($variation_input_name, $variation_input_value);
    $this
      ->assertNoFieldByName($option_set_type_name);
    $this
      ->assertNoFieldByName($block_title_name);
    $this
      ->assertFieldByName($element_url_name);

    // Cancel the creation of the variation set.
    $this
      ->drupalPostAJAX(NULL, array(), array(
      'cancel_element_option_set_0' => t('Cancel'),
    ));
    $this
      ->assertFieldByname($variation_input_name, $variation_input_value);
    $this
      ->assertNoFieldByName($option_set_type_name);
    $this
      ->assertNoFieldByName($block_title_name);
    $this
      ->assertNoFieldByName($element_url_name);

    // Now test the selection process when there is an existing option set.

    /* Temporarily removed: https://www.drupal.org/node/2505247
        $this->createPersonalizedBlock(1, $agent);

        // Set the variation set handling
        $this->drupalget('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
        $this->assertNoFieldByName($block_title_name);
        $this->assertNoFieldByName($element_url_name);
        $this->assertNoFieldByName('variations[add_variation][option_set_type]');
        $this->assertFieldByName('variations[add_variation][variation_set_handling]');
        $edit = array(
          'variations[add_variation][variation_set_handling]' => ACQUIA_LIFT_DECISION_LOCKSTEP,
        );
        $this->drupalPostAJAX(NULL, $edit, 'variations[add_variation][variation_set_handling]');
        // Now we can set the type of option set to create.
        $edit = array(
          'variations[add_variation][option_set_type]' => 'block',
        );
        $this->drupalPostAJAX(NULL, $edit, 'variations[add_variation][option_set_type]');
        // And finally there should be the new block form.
        $this->assertFieldByName($block_title_name);

        // Finally test adding option sets once they are already multiple.
        $this->createPersonalizedBlock(2, $agent);
        $agent->data['variation_set_handling'] = ACQUIA_LIFT_DECISION_LOCKSTEP;
        personalize_agent_save($agent);

        $this->drupalget('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
        $this->assertText('Variation sets (Lock step)');
        $this->assertFieldByName('variations[add_variation][option_set_type]');
        $this->assertNoFieldByName('variations[add_variation][variation_set_handling]');
        $this->assertNoFieldByName($block_title_name);
        $this->assertNoFieldByName($element_url_name);
        $edit = array(
          'variations[add_variation][option_set_type]' => 'block',
        );
        $this->drupalPostAJAX(NULL, $edit, 'variations[add_variation][option_set_type]');
        // The new block form should display without selecting variation handling.
        $this->assertFieldByName($block_title_name);
        */
  }

  /**
   * Test block variation set creation.
   */
  function testWhatBlockForm() {
    $this
      ->drupalLogin($this->managerUser);
    $agent = $this
      ->createTargetingAgent();

    // Create a personalized block from existing blocks.
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
    $this
      ->drupalPostAJAX(NULL, array(), $this->addVariationSetElement);

    // Indicate a block variation set type.
    $edit = array(
      'variations[editing][new][0][option_set_type]' => 'block',
    );
    $this
      ->drupalPostAJAX(NULL, $edit, 'variations[editing][new][0][option_set_type]');
    $edit = array(
      'variations[editing][new][0][block][content][title]' => 'Muppets',
      'variations[editing][new][0][block][content][pblock_wrapper][blocks][0][option_label]' => 'My variation 1',
      'variations[editing][new][0][block][content][pblock_wrapper][blocks][0][block][bid]' => 'comment_delta_recent',
      'variations[editing][new][0][block][content][pblock_wrapper][blocks][1][option_label]' => 'My variation 2',
      'variations[editing][new][0][block][content][pblock_wrapper][blocks][1][block][bid]' => 'node_delta_recent',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $agent->machine_name,
      'step' => 'variations',
    )));
    $option_sets = personalize_option_set_load_by_agent($agent->machine_name);
    $this
      ->assertEqual(count($option_sets), 1);
    $option_set = reset($option_sets);
    $this
      ->assertEqual(count($option_set->options), 2);
    $this
      ->assertEqual($option_set->label, t('Muppets'));
    $this
      ->assertEqual($option_set->options[0]['option_label'], 'My variation 1');
    $this
      ->assertEqual($option_set->options[0]['bid'], 'comment_delta_recent');
    $this
      ->assertEqual($option_set->options[1]['option_label'], 'My variation 2');
    $this
      ->assertEqual($option_set->options[1]['bid'], 'node_delta_recent');

    // Now go to the variations page and verify the new option set is available.
    $this
      ->resetAll();
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
    $this
      ->assertFieldByName('variations[editing][option_sets][option_set_' . $option_set->osid . '][content][title]', 'Muppets');
    $this
      ->assertOptionSelected('edit-variations-editing-option-sets-option-set-' . $option_set->osid . '-content-pblock-wrapper-blocks-0-block-bid', 'comment_delta_recent');
    $this
      ->assertOptionSelected('edit-variations-editing-option-sets-option-set-' . $option_set->osid . '-content-pblock-wrapper-blocks-1-block-bid', 'node_delta_recent');

    // Edit the variation set title change the second block to a new block
    // created inline.
    $edit = array(
      'variations[editing][option_sets][option_set_' . $option_set->osid . '][content][title]' => 'Great Muppet Caper',
      'variations[editing][option_sets][option_set_' . $option_set->osid . '][content][pblock_wrapper][blocks][0][block][bid]' => 'comment_delta_recent',
      'variations[editing][option_sets][option_set_' . $option_set->osid . '][content][pblock_wrapper][blocks][1][block][block_type]' => 'add',
      'variations[editing][option_sets][option_set_' . $option_set->osid . '][content][pblock_wrapper][blocks][1][block][add][title]' => 'Kermit',
      'variations[editing][option_sets][option_set_' . $option_set->osid . '][content][pblock_wrapper][blocks][1][block][add][info]' => 'Piggy',
      'variations[editing][option_sets][option_set_' . $option_set->osid . '][content][pblock_wrapper][blocks][1][block][add][body][value]' => 'complicated',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $agent->machine_name,
      'step' => 'variations',
    )));
    $option_sets = personalize_option_set_load_by_agent($agent->machine_name, TRUE);
    $this
      ->assertEqual(count($option_sets), 1);
    $option_set = reset($option_sets);
    $this
      ->assertEqual(count($option_set->options), 2);
    $this
      ->assertEqual($option_set->label, 'Great Muppet Caper');
    $this
      ->assertEqual($option_set->options[1]['bid'], 'block_delta_1');

    // Now go to the variations page test the advanced options
    $this
      ->resetAll();
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
    $edit = array(
      'variations[editing][option_sets][option_set_' . $option_set->osid . '][advanced][stateful]' => 1,
      'variations[editing][option_sets][option_set_' . $option_set->osid . '][advanced][preview_link]' => 'invalid url',
      'variations[editing][option_sets][option_set_' . $option_set->osid . '][advanced][executor]' => 'callback',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $agent->machine_name,
      'step' => 'variations',
    )));
    $this
      ->assertText('You have specified an invalid path');
    $edit['variations[editing][option_sets][option_set_' . $option_set->osid . '][advanced][preview_link]'] = '<front>';
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $agent->machine_name,
      'step' => 'variations',
    )));
    $option_sets = personalize_option_set_load_by_agent($agent->machine_name, TRUE);
    $this
      ->assertEqual(count($option_sets), 1);
    $option_set = reset($option_sets);
    $this
      ->assertEqual(count($option_set->options), 2);
    $this
      ->assertEqual($option_set->label, 'Great Muppet Caper');
    $this
      ->assertEqual($option_set->stateful, 1);
    $this
      ->assertEqual($option_set->preview_link, '<front>');
    $this
      ->assertEqual($option_set->executor, 'callback');
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
    $osid = $option_set->osid;
    foreach ($option_set->options as $option) {
      $preview_link = url('<front>', array(
        'query' => array(
          PERSONALIZE_PRESELECTION_PARAM => 'osid-' . $osid . '--' . $option['option_id'],
        ),
      ));
      $this
        ->assertLinkByHref($preview_link);
    }
  }

  /**
   * Test element variation set creation.
   */
  function testWhatElementForm() {
    $admin_user = $this
      ->drupalCreateUser(array(
      'access administration pages',
      'manage personalized content',
      'use advanced personalize elements features',
    ));
    $this
      ->drupalLogin($admin_user);
    $agent = $this
      ->createTargetingAgent();
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
    $this
      ->drupalPostAJAX(NULL, array(), $this->addVariationSetElement);

    // Indicate an element variation set type.
    $edit = array(
      'variations[editing][new][0][option_set_type]' => 'element',
    );
    $this
      ->drupalPostAJAX(NULL, $edit, 'variations[editing][new][0][option_set_type]');

    // Invalid url
    $edit = array(
      'variations[editing][new][0][element][content][url]' => 'invalid url',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_element_navigate'));
    $this
      ->assertText('You have specified an invalid path');

    // Valid external url
    $edit = array(
      'variations[editing][new][0][element][content][url]' => 'http://www.google.com',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_element_navigate'));
    $this
      ->assertNoText('You have specified an invalid path');

    // Adjust the current url to match expected URLs across environments.
    $current_url = $this->url;
    if (substr($current_url, -1) != '/') {
      $current_url .= '/';
    }

    // Assert current url's prefix a google url (but possibly already redirected by IP's country).
    $current_url_expected_prefix = 'http://www.google.';
    $current_url_expected_prefix_length = strlen($current_url_expected_prefix);
    $this
      ->assertTrue(substr($current_url, 0, $current_url_expected_prefix_length) === $current_url_expected_prefix);

    // Valid url by alias
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
    $this
      ->drupalPostAJAX(NULL, array(), $this->addVariationSetElement);
    $edit = array(
      'variations[editing][new][0][option_set_type]' => 'element',
    );
    $this
      ->drupalPostAJAX(NULL, $edit, 'variations[editing][new][0][option_set_type]');
    $edit = array(
      'variations[editing][new][0][element][content][url]' => 'admin/structure',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_element_navigate'));
    $this
      ->assertNoText('You have specified an invalid path');
    $this
      ->assertUrl('admin/structure');

    // Valid url by path
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
    $this
      ->drupalPostAJAX(NULL, array(), $this->addVariationSetElement);

    // Indicate an element variation set type.
    $edit = array(
      'variations[editing][new][0][option_set_type]' => 'element',
    );
    $this
      ->drupalPostAJAX(NULL, $edit, 'variations[editing][new][0][option_set_type]');
    $edit = array(
      'variations[editing][new][0][element][content][url]' => 'node',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_element_navigate'));
    $this
      ->assertNoText('You have specified an invalid path');
    $this
      ->assertUrl('node');

    // Check the settings for toolbar integration.
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertEqual($settings['acquia_lift']['toolbarEditMode'], 'element');

    // Now navigate to another page and make sure that the settings are gone.
    $this
      ->drupalGet('admin/structure/personalize');
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertTrue(empty($settings['acquia_lift']['toolbarEditMode']));

    // Create an element variation for our agent.
    $option_set = $this
      ->createPersonalizeElementsOptionSet($agent->machine_name, array(
      'num_options' => 1,
      'add_control' => TRUE,
      'pages' => 'node',
    ));

    // Go to the edit page and verify that this option set is displayed and
    // links to its "pages" page for editing.
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
    $this
      ->assertText('Element test set 1');

    // Check the preview links are displayed.
    $osid = $option_set->osid;
    foreach ($option_set->options as $option) {
      $this
        ->assertLinkByHref(url('node', array(
        PERSONALIZE_PRESELECTION_PARAM => 'osid-' . $osid . '--' . $option['option_id'],
      )));
    }

    // Now verify that the edit link goes to the node page as well.
    $this
      ->clickLink(t('Edit variations in context'));
    $this
      ->assertUrl('node');

    // Settings should include indicators for deleting and editing option sets.
    $js_osid = personalize_stringify_osid($option_set->osid);
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertFalse($settings['acquia_lift']['option_sets'][$js_osid][PERSONALIZE_CONTROL_OPTION_ID]['editable']);
    $this
      ->assertFalse($settings['acquia_lift']['option_sets'][$js_osid][PERSONALIZE_CONTROL_OPTION_ID]['deletable']);
    $this
      ->assertTrue($settings['acquia_lift']['option_sets'][$js_osid]['option-A']['editable']);
    $this
      ->assertTrue($settings['acquia_lift']['option_sets'][$js_osid]['option-A']['deletable']);

    // Start the campaign and the elements should not be deletable.
    $this
      ->createTestFromOptionSet($agent, $option_set);
    $this
      ->drupalPost('admin/structure/personalize/manage/' . $agent->machine_name . '/review', array(), t('Start'));
    $this
      ->drupalGet('');
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertFalse($settings['acquia_lift']['option_sets'][$js_osid][PERSONALIZE_CONTROL_OPTION_ID]['editable']);
    $this
      ->assertFalse($settings['acquia_lift']['option_sets'][$js_osid][PERSONALIZE_CONTROL_OPTION_ID]['deletable']);
    $this
      ->assertTrue($settings['acquia_lift']['option_sets'][$js_osid]['option-A']['editable']);
    $this
      ->assertFalse($settings['acquia_lift']['option_sets'][$js_osid]['option-A']['deletable']);

    // Add another option to the option set that is not targeted.
    $option_set->options[] = array(
      'option_id' => 'option-B',
      'option_label' => 'Option B',
      'personalize_elements_content' => 'Yaaaaaay!',
    );
    $option_set = personalize_option_set_save($option_set);
    $this
      ->resetAll();

    // The new option should be deletable.
    $this
      ->drupalGet('');
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertFalse($settings['acquia_lift']['option_sets'][$js_osid][PERSONALIZE_CONTROL_OPTION_ID]['editable']);
    $this
      ->assertFalse($settings['acquia_lift']['option_sets'][$js_osid][PERSONALIZE_CONTROL_OPTION_ID]['deletable']);
    $this
      ->assertTrue($settings['acquia_lift']['option_sets'][$js_osid]['option-A']['editable']);
    $this
      ->assertFalse($settings['acquia_lift']['option_sets'][$js_osid]['option-A']['deletable']);
    $this
      ->assertTrue($settings['acquia_lift']['option_sets'][$js_osid]['option-B']['editable']);
    $this
      ->assertTrue($settings['acquia_lift']['option_sets'][$js_osid]['option-B']['deletable']);

    // Pause the agent and all options should be editable and deletable.
    personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_PAUSED);
    $this
      ->drupalGet('');
    $settings = $this
      ->drupalGetSettings();
    $this
      ->assertFalse($settings['acquia_lift']['option_sets'][$js_osid][PERSONALIZE_CONTROL_OPTION_ID]['editable']);
    $this
      ->assertFalse($settings['acquia_lift']['option_sets'][$js_osid][PERSONALIZE_CONTROL_OPTION_ID]['deletable']);
    $this
      ->assertTrue($settings['acquia_lift']['option_sets'][$js_osid]['option-A']['editable']);
    $this
      ->assertTrue($settings['acquia_lift']['option_sets'][$js_osid]['option-A']['deletable']);
    $this
      ->assertTrue($settings['acquia_lift']['option_sets'][$js_osid]['option-B']['editable']);
    $this
      ->assertTrue($settings['acquia_lift']['option_sets'][$js_osid]['option-B']['deletable']);

    // Verify that the elements variation can have general edits made from
    // the campaign workflow.
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
    $edit = array(
      'variations[editing][option_sets][option_set_' . $option_set->osid . '][content][label]' => 'Element test set 1 - EDIT',
      'variations[editing][option_sets][option_set_' . $option_set->osid . '][content][options][option-A][option_label]' => 'Option A - EDIT',
      'variations[editing][option_sets][option_set_' . $option_set->osid . '][advanced][pages_all]' => 0,
      'variations[editing][option_sets][option_set_' . $option_set->osid . '][advanced][pages]' => "node\nadmin/*",
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $agent->machine_name,
      'step' => 'variations',
    )));
    $option_set = personalize_option_set_load($option_set->osid, TRUE);
    $this
      ->assertTrue('Element test set 1 - EDIT', $option_set->label);
    foreach ($option_set->options as $option) {
      if ($option['option_id'] == 'option-A') {
        $this
          ->assertTrue('Option A - EDIT', $option_set->label);
      }
    }
    $this
      ->assertEqual($option_set->data['pages'], "node\nadmin/*");
    $this
      ->assertEqual($option_set->preview_link, 'node');

    // Now add a javascript personalize elements variation.
    $js_option_set = $this
      ->createPersonalizeElementsOptionSet($agent->machine_name, array(
      'type' => 'runJS',
      'selector' => '',
      'add_control' => TRUE,
      'num_options' => 2,
    ));
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
    $this
      ->clickLink('Edit variations');
    $this
      ->assertOptionSelected('edit-variation-type', 'runJS');
    $edit = array(
      'title' => 'JavaScript variation set',
    );
    $this
      ->drupalPost(NULL, $edit, t('Save'));

    // Should be redirected back to the "What" page
    $this
      ->assertUrl('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
    $this
      ->assertFieldByName('variations[editing][option_sets][option_set_' . $js_option_set->osid . '][content][label]', 'JavaScript variation set');
  }

  /**
   * Test the personalize fields view of the "What" campaign subform.
   */
  function testWhatFieldsForm() {
    module_enable(array(
      'personalize_fields',
    ));
    $this
      ->resetAll();
    $admin_user = $this
      ->drupalCreateUser(array(
      'access administration pages',
      'administer site configuration',
      'access content',
      'administer content types',
      'administer nodes',
      'bypass node access',
      'manage personalized content',
    ));
    $this
      ->drupalLogin($admin_user);

    // Add personalizable field to the article node type.
    $this
      ->createPersonalizedArticleField();
    list($node, $os, $agent_name) = $this
      ->createPersonalizedField();
    $this
      ->drupalGet("admin/structure/personalize/manage/{$agent_name}/variations");

    // Text should be shown in preview.
    $this
      ->assertText('first value');
    $this
      ->assertText('second value');

    // Basic variation editing should be available.
    $edit = array(
      'variations[editing][option_sets][option_set_' . $os->osid . '][content][label]' => 'Fields test edit',
      'variations[editing][option_sets][option_set_' . $os->osid . '][content][options][first-value][option_label]' => 'Option A - EDIT',
      'variations[editing][option_sets][option_set_' . $os->osid . '][content][options][second-value][option_label]' => 'Option B - EDIT',
      'variations[editing][option_sets][option_set_' . $os->osid . '][advanced][preview_link]' => 'node/' . $node->nid,
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $agent_name,
      'step' => 'variations',
    )));

    // Go back and verify the changes.
    $this
      ->drupalGet("admin/structure/personalize/manage/{$agent_name}/variations");
    $this
      ->assertFieldByName('variations[editing][option_sets][option_set_' . $os->osid . '][content][label]', 'Fields test edit');
    $this
      ->assertFieldByName('variations[editing][option_sets][option_set_' . $os->osid . '][content][options][first-value][option_label]', 'Option A - EDIT');
    $this
      ->assertFieldByName('variations[editing][option_sets][option_set_' . $os->osid . '][content][options][second-value][option_label]', 'Option B - EDIT');
    $this
      ->assertText('first value');
    $this
      ->assertText('second value');
    $this
      ->assertLinkByHref(url('node/' . $node->nid, array(
      'query' => array(
        PERSONALIZE_PRESELECTION_PARAM => personalize_stringify_osid($os->osid) . '--first-value',
      ),
    )));
    $this
      ->assertLinkByHref(url('node/' . $node->nid, array(
      'query' => array(
        PERSONALIZE_PRESELECTION_PARAM => personalize_stringify_osid($os->osid) . '--second-value',
      ),
    )));

    // Check the link to edit in context.
    $this
      ->clickLink(t('Edit variations in context'));
    $this
      ->assertUrl('node/' . $node->nid . '/edit', array(
      'query' => array(
        'destination' => "admin/structure/personalize/manage/{$agent_name}/variations",
      ),
    ));
    $this
      ->drupalPost(NULL, array(), t('Save'));
    $this
      ->assertUrl("admin/structure/personalize/manage/{$agent_name}/variations");
  }

  /**
   * Test lock-step combinations of variation sets.
   */
  function testWhatLockStep() {
    $error_heading = "Let's fix this";
    $error_message = 'Variation sets must contain an equal number of variations.';
    $this
      ->drupalLogin($this->managerUser);
    $agent = $this
      ->createTargetingAgent();

    // Create a personalized block from existing blocks.
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');
    $this
      ->assertNoText($error_heading);
    $this
      ->assertNoText($error_message);

    // Add two variation sets.
    $this
      ->drupalPostAJAX(NULL, array(), $this->addVariationSetElement);
    $this
      ->drupalPostAJAX(NULL, array(), $this->addVariationSetElement);
    $edit = array(
      'variations[editing][new][0][option_set_type]' => 'block',
    );
    $this
      ->drupalPostAJAX(NULL, $edit, 'variations[editing][new][0][option_set_type]');
    $edit = array(
      'variations[editing][new][1][option_set_type]' => 'block',
    );
    $this
      ->drupalPostAJAX(NULL, $edit, 'variations[editing][new][1][option_set_type]');
    $this
      ->drupalPostAJAX(NULL, array(), 'blocks_add_variation_add_1');
    $edit = array(
      'variations[editing][new][0][block][content][title]' => 'Muppets',
      'variations[editing][new][0][block][content][pblock_wrapper][blocks][0][option_label]' => 'Muppets variation 1',
      'variations[editing][new][0][block][content][pblock_wrapper][blocks][0][block][bid]' => 'comment_delta_recent',
      'variations[editing][new][0][block][content][pblock_wrapper][blocks][1][option_label]' => 'Muppets variation 2',
      'variations[editing][new][0][block][content][pblock_wrapper][blocks][1][block][bid]' => 'node_delta_recent',
      'variations[editing][new][1][block][content][title]' => 'Sesame',
      'variations[editing][new][1][block][content][pblock_wrapper][blocks][0][option_label]' => 'Sesame variation 1',
      'variations[editing][new][1][block][content][pblock_wrapper][blocks][0][block][bid]' => 'system_delta_powered-by',
      'variations[editing][new][1][block][content][pblock_wrapper][blocks][1][option_label]' => 'Sesme variation 2',
      'variations[editing][new][1][block][content][pblock_wrapper][blocks][1][block][bid]' => 'system_delta_help',
      'variations[editing][new][1][block][content][pblock_wrapper][blocks][2][option_label]' => 'Sesame variation 3',
      'variations[editing][new][1][block][content][pblock_wrapper][blocks][2][block][bid]' => 'user_delta_new',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $agent->machine_name,
      'step' => 'variations',
    )));
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/variations');

    // Should still be on the variations page only now there should be a
    // warning message.
    $this
      ->assertText($error_heading);
    $this
      ->assertText($error_message);

    // Remove the extra variation.
    $option_sets = personalize_option_set_load_by_agent($agent->machine_name);
    $second_os = end($option_sets);
    $edit = array(
      'variations[editing][option_sets][option_set_' . $second_os->osid . '][content][pblock_wrapper][blocks][2][block][bid]' => '',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_save'));

    // Verify that the error message is gone.
    $this
      ->assertNoText($error_heading);
    $this
      ->assertNoText($error_message);
  }

}
class AcquiaLiftWebTestCampaignWizardTargeting extends AcquiaLiftWebTestCampaignWizardBase {
  public static function getInfo() {
    return array(
      'name' => t('Acquia Lift Web Tests - Personalization Wizard Targeting'),
      'description' => t('Tests functionality related to the personalization management wizard targeting forms.'),
      'group' => t('Personalize'),
    );
  }

  /**
   * Verify that audience-style targeting is only available for Acquia Lift
   * Target agents.
   */
  function testAudienceAvailability() {
    $audience_input_name = key($this->addTargetAudienceElement);
    $audience_input_value = reset($this->addTargetAudienceElement);

    // For this test we need to delete the tags vocabulary because otherwise it
    // will show up as an available context via personalize_taxonomy_context.
    $tags_vocab = taxonomy_vocabulary_machine_name_load('tags');
    taxonomy_vocabulary_delete($tags_vocab->vid);
    $this
      ->resetAll();
    $target_agent_data = $this
      ->createTargetingAgent();
    $target_name = $target_agent_data->machine_name;

    // No audiences should be shown unless contexts are available.
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $target_name . '/targeting');
    $this
      ->assertNoFieldByName($audience_input_name, $audience_input_value);
    $this
      ->assertText('Either your website does not have any enabled targeting contexts, or there are no targeting contexts available for your personalization.');
    module_enable(array(
      'personalize_url_context',
    ));
    $this
      ->resetAll();
    $this
      ->resetAll();

    // No audiences should show before option sets are created.
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $target_name . '/targeting');
    $this
      ->assertNoFieldByName($audience_input_name, $audience_input_value);
    $this
      ->assertText('You must create variation sets before targeting.');

    // Now add an option set.
    $this
      ->createOptionSet(1, array(
      'agent' => $target_name,
      'plugin' => 'type1',
      'num_options' => 2,
    ));
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $target_name . '/targeting');
    $this
      ->assertFieldByName($audience_input_name, $audience_input_value);
    $this
      ->assertNoText('You must create variation sets before targeting.');
  }

  /**
   * Test the audience functionality.
   */
  function testTargeting() {
    $audience_input_name = key($this->addTargetAudienceElement);
    $audience_input_value = reset($this->addTargetAudienceElement);
    $first_agent = $this
      ->createTargetingAgent();
    $first_option_set = $this
      ->createOptionSet(1, array(
      'agent' => $first_agent->machine_name,
      'plugin' => 'type1',
      'num_options' => 3,
    ));
    $option_id_1 = $first_option_set->options[0]['option_id'];
    $option_id_2 = $first_option_set->options[1]['option_id'];
    $option_id_3 = $first_option_set->options[2]['option_id'];

    // Create user profile fields that we can use for targeting.
    $user_profile_field_1 = $this
      ->createUserProfileField();
    $context_1 = str_replace('field_', '', $user_profile_field_1['field_name']);
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $first_agent->machine_name . '/targeting');
    $this
      ->drupalPostAJAX(NULL, array(), $this->addTargetAudienceElement);

    // There should now be a form to add a new audience as well as the button
    // to generate a new add form.
    $this
      ->assertFieldByName($audience_input_name, $audience_input_value);
    $this
      ->assertFieldByName('audiences[new][0][details][name]');
    $edit = array(
      'audiences[new][0][details][name]' => 'Muppet fans',
      'audiences[new][0][details][mapping][contexts][0][context]' => 'user_profile_context' . PERSONALIZE_TARGETING_ADMIN_SEPARATOR . $context_1,
      'audiences[new][0][details][mapping][contexts][0][value][match]' => 'some value',
      'audiences[new][0][details][mapping][contexts][0][value][operator]' => 'equals',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $first_agent->machine_name,
      'step' => 'targeting',
    )));
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $first_agent->machine_name . '/targeting');

    // Now there should be an existing audience as well as a button to create
    // a new audience.
    $this
      ->assertFieldByName('audiences[existing][muppet-fans][details][name]', 'Muppet fans');
    $this
      ->assertFieldByName($audience_input_name, $audience_input_value);

    // Add a new audience and edit the existing audience.
    $this
      ->drupalPostAJAX(NULL, array(), $this->addTargetAudienceElement);
    $edit = array(
      'audiences[existing][muppet-fans][details][name]' => 'Muppet mania',
      'audiences[existing][muppet-fans][details][mapping][contexts][0][value][match]' => 'Kermit fans',
      'audiences[new][0][details][name]' => 'Others',
      'audiences[new][0][details][mapping][contexts][0][context]' => 'user_profile_context' . PERSONALIZE_TARGETING_ADMIN_SEPARATOR . $context_1,
      'audiences[new][0][details][mapping][contexts][0][value][operator]' => 'equals',
      'audiences[new][0][details][mapping][contexts][0][value][match]' => 'Sad people',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $first_agent->machine_name,
      'step' => 'targeting',
    )));
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $first_agent->machine_name . '/targeting');

    // Now there should be two existing audiences as well as a button to create
    // a new audience.
    $this
      ->assertFieldByName('audiences[existing][muppet-fans][details][name]', 'Muppet mania');
    $this
      ->assertFieldByname('audiences[existing][muppet-fans][details][mapping][contexts][0][value][match]', 'Kermit fans');
    $this
      ->assertFieldByName('audiences[existing][others][details][name]', 'Others');
    $this
      ->assertFieldByName('audiences[existing][others][details][mapping][contexts][0][context]', 'user_profile_context' . PERSONALIZE_TARGETING_ADMIN_SEPARATOR . $context_1);
    $this
      ->assertOptionSelected('edit-audiences-existing-others-details-mapping-contexts-0-value-operator', 'equals');
    $this
      ->assertFieldByName('audiences[existing][others][details][mapping][contexts][0][value][match]', 'Sad people');
    $this
      ->assertFieldByName($audience_input_name, $audience_input_value);

    // Adjust the weights and verify that the "Everyone else" has the highest.
    module_load_include('inc', 'acquia_lift', 'acquia_lift.admin');
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $first_agent->machine_name . '/targeting');
    $edit = array(
      'audiences[existing][muppet-fans][details][weight]' => 50,
      'audiences[existing][others][details][weight]' => 75,
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $first_agent->machine_name,
      'step' => 'targeting',
    )));
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $first_agent->machine_name . '/targeting');
    $option_set = acquia_lift_get_option_set_for_targeting($first_agent->machine_name);
    $this
      ->assertEqual($option_set->targeting['muppet-fans']['weight'], 50);
    $this
      ->assertEqual($option_set->targeting['others']['weight'], 75);
    $this
      ->assertEqual($option_set->targeting['everyone-else']['weight'], 85);
    $edit = array(
      'audiences[existing][muppet-fans][details][weight]' => 5,
      'audiences[existing][others][details][weight]' => 0,
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $first_agent->machine_name,
      'step' => 'targeting',
    )));
    $this
      ->resetAll();
    $option_set = acquia_lift_get_option_set_for_targeting($first_agent->machine_name);
    $this
      ->assertEqual($option_set->targeting['muppet-fans']['weight'], 5);
    $this
      ->assertEqual($option_set->targeting['others']['weight'], 0);
    $this
      ->assertEqual($option_set->targeting['everyone-else']['weight'], 15);
    $first_agent = personalize_agent_load($first_agent->machine_name);

    // Confirm that an error message is shown on review.
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $first_agent->machine_name . '/review');
    $this
      ->assertText('You have not assigned any variations to audiences');

    // Test assignments saves as anticipated.
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $first_agent->machine_name . '/targeting');

    // There are no targeting assignments so there should be no messages.
    $this
      ->assertNoText('The targeting settings shown here do not match what is currently implemented for this personalization.');
    $this
      ->assertNoText('The targeting settings shown here represent what is currently implemented for this personalization.');

    // All audiences should not have any assignments by default.
    $this
      ->assertNoOptionSelected('edit-audiences-existing-everyone-else-assignment', $option_id_1);
    $this
      ->assertNoOptionSelected('edit-audiences-existing-everyone-else-assignment', $option_id_2);
    $this
      ->assertNoOptionSelected('edit-audiences-existing-everyone-else-assignment', $option_id_3);
    $this
      ->assertNoOptionSelected('edit-audiences-existing-muppet-fans-assignment', $option_id_1);
    $this
      ->assertNoOptionSelected('edit-audiences-existing-muppet-fans-assignment', $option_id_2);
    $this
      ->assertNoOptionSelected('edit-audiences-existing-muppet-fans-assignment', $option_id_3);
    $this
      ->assertNoOptionSelected('edit-audiences-existing-others-assignment', $option_id_1);
    $this
      ->assertNoOptionSelected('edit-audiences-existing-others-assignment', $option_id_2);
    $this
      ->assertNoOptionSelected('edit-audiences-existing-others-assignment', $option_id_3);
    $edit = array(
      'audiences[existing][muppet-fans][assignment_order]' => $option_id_1 . ',' . $option_id_2,
      'audiences[existing][others][assignment_order]' => $option_id_3,
      'audiences[existing][everyone-else][assignment_order]' => $option_id_1,
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $first_agent->machine_name,
      'step' => 'targeting',
    )));

    // The targeting should be saved in the agent property.
    $first_agent = personalize_agent_load($first_agent->machine_name, TRUE);
    $expected_agent_targeting = array(
      'muppet-fans' => array(
        $option_id_1,
        $option_id_2,
      ),
      'others' => array(
        $option_id_3,
      ),
      'everyone-else' => array(
        $option_id_1,
      ),
    );
    $this
      ->assertEqual($expected_agent_targeting, $first_agent->data['lift_targeting']);

    // The targeting should not have been saved to the option set yet.
    acquia_lift_get_structure_from_targeting(personalize_option_set_load($first_option_set->osid, TRUE));
    $this
      ->assertTrue(empty($option_set->targeting['muppet-fans']['option_id']));
    $this
      ->assertTrue(empty($option_set->targeting['muppet-fans']['osid']));
    $this
      ->assertTrue(empty($option_set->targeting['others']['option_id']));
    $this
      ->assertTrue(empty($option_set->targeting['others']['osid']));
    $this
      ->assertTrue(empty($option_set->targeting['everyone-else']['option_id']));
    $this
      ->assertTrue(empty($option_set->targeting['everyone-else']['osid']));

    // A message should not display to indicate that the targeting isn't
    // finalized because the agent is still not started.
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $first_agent->machine_name . '/targeting');
    $this
      ->assertNoText('The targeting settings shown here do not match what is currently implemented for this personalization.');
    $this
      ->assertNoText('The targeting settings shown here represent what is currently implemented for this personalization.');

    // Delete an audience and verify that all adjusts accordingly.
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $first_agent->machine_name . '/audience/others/delete');
    $this
      ->drupalPost(NULL, array(), t('Delete'));
    $first_agent = personalize_agent_load($first_agent->machine_name, TRUE);
    $expected_agent_targeting = array(
      'muppet-fans' => array(
        $option_id_1,
        $option_id_2,
      ),
      'everyone-else' => array(
        $option_id_1,
      ),
    );
    $this
      ->assertEqual($expected_agent_targeting['muppet-fans'], array_values($first_agent->data['lift_targeting']['muppet-fans']));
    $this
      ->assertEqual($expected_agent_targeting['everyone-else'], array_values($first_agent->data['lift_targeting']['everyone-else']));
    $this
      ->assertFalse(isset($first_agent->data['lift_targeting']['others']));

    // Confirm that an error message is no longer shown on review.
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $first_agent->machine_name . '/review');
    $this
      ->assertNoText('You have not assigned any variations to audiences');

    // Save the targeting structure and start the agent.
    $this
      ->drupalPost(NULL, array(), $this
      ->getButton('wizard_start'));

    // Pause the agent in order to make changes.
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $first_agent->machine_name . '/targeting');
    $this
      ->drupalPost(NULL, array(), t("Pause"));

    // Make changes and verify the messaging.
    $edit = array(
      'audiences[existing][muppet-fans][assignment_order]' => $option_id_2,
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $first_agent->machine_name,
      'step' => 'targeting',
    )));
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $first_agent->machine_name . '/targeting');
    $this
      ->assertText('The targeting settings shown here do not match what is currently implemented for this personalization.');
    $this
      ->assertNoText('The targeting settings shown here represent what is currently implemented for this personalization.');

    // Revert the changes and verify.
    $this
      ->drupalPost(NULL, NULL, t('Revert changes'));
    $this
      ->assertText(t('Are you sure you want to revert the targeting changes'));
    $this
      ->drupalPost(NULL, NULL, t('Revert changes'));
    $this
      ->resetAll();
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $first_agent->machine_name . '/targeting');
    $this
      ->assertNoText('The targeting settings shown here do not match what is currently implemented for this personalization.');
    $this
      ->assertText('The targeting settings shown here represent what is currently implemented for this personalization.');
    $this
      ->assertOptionSelected('edit-audiences-existing-muppet-fans-assignment', $option_id_1);
    $this
      ->assertOptionSelected('edit-audiences-existing-muppet-fans-assignment', $option_id_2);
    $this
      ->assertOptionSelected('edit-audiences-existing-everyone-else-assignment', $option_id_1);

    // Add an option to the existing option set and verify that it appears as
    // unassigned but available for targeting.
    $unassigned_id = personalize_generate_option_id(3);
    $first_option_set->options[] = array(
      'option_id' => $unassigned_id,
      'option_label' => personalize_generate_option_label(3),
    );
    personalize_option_set_save($first_option_set);
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $first_agent->machine_name . '/targeting');
    $this
      ->assertOptionSelected('edit-variations-options-assignment', $unassigned_id);
    $this
      ->assertOptionSelected('edit-variations-options-assignment', $option_id_1);
    $this
      ->assertOptionSelected('edit-variations-options-assignment', $option_id_2);
    $this
      ->assertOptionSelected('edit-variations-options-assignment', $option_id_3);
    $this
      ->assertOptionSelected('edit-audiences-existing-muppet-fans-assignment', $option_id_1);
    $this
      ->assertOptionSelected('edit-audiences-existing-muppet-fans-assignment', $option_id_2);
    $this
      ->assertOptionSelected('edit-audiences-existing-everyone-else-assignment', $option_id_1);
  }

  /**
   * Test doing a straight test, i.e. all variations assigned to "Everyone Else".
   */
  function testNoTargeting() {
    module_load_include('inc', 'acquia_lift', 'acquia_lift.admin');

    // Create user profile fields that we can use to force enabling targeting.
    $user_profile_field_1 = $this
      ->createUserProfileField();
    $first_agent = $this
      ->createTargetingAgent();
    $first_option_set = $this
      ->createOptionSet(1, array(
      'agent' => $first_agent->machine_name,
      'plugin' => 'type1',
      'num_options' => 3,
    ));
    $option_id_1 = $first_option_set->options[0]['option_id'];
    $option_id_2 = $first_option_set->options[1]['option_id'];
    $option_id_3 = $first_option_set->options[2]['option_id'];

    // Assign all options to the everyone audience.
    $edit = array(
      'audiences[existing][everyone-else][assignment_order]' => $option_id_1 . ',' . $option_id_2 . ',' . $option_id_3,
    );
    $this
      ->drupalPost('admin/structure/personalize/manage/' . $first_agent->machine_name . '/targeting', $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $first_agent->machine_name,
      'step' => 'targeting',
    )));

    // The targeting should be saved in the agent property.
    $first_agent = personalize_agent_load($first_agent->machine_name, TRUE);
    $expected_agent_targeting = array(
      'everyone-else' => array(
        $option_id_1,
        $option_id_2,
        $option_id_3,
      ),
    );
    $this
      ->assertEqual($expected_agent_targeting, $first_agent->data['lift_targeting']);
    $option_set = acquia_lift_get_option_set_for_targeting($first_agent->machine_name);

    // The targeting should not have been saved to the option set yet.
    $this
      ->assertTrue(empty($option_set->targeting['everyone-else']['option_id']));
    $this
      ->assertTrue(empty($option_set->targeting['everyone-else']['osid']));

    // Hit the start button on the review form to implement the targeting
    $this
      ->drupalPost('admin/structure/personalize/manage/' . $first_agent->machine_name . '/review', array(), $this
      ->getButton('wizard_start'));
    personalize_agent_load($first_agent->machine_name, TRUE);
    $this
      ->resetAll();
    $option_set = personalize_option_set_load($option_set->osid, TRUE);

    // The targeting should now have been saved to the option set.
    $this
      ->assertFalse(empty($option_set->targeting['everyone-else']['osid']));
  }
  function testWinnerSelectionAvailability() {

    // Create user profile fields that we can use for targeting.
    $user_profile_field_1 = $this
      ->createUserProfileField();
    $context_1 = str_replace('field_', '', $user_profile_field_1['field_name']);

    // Create an agent with option set but no tests.
    $agent = $this
      ->createTargetingAgent();
    $option_set = $this
      ->createOptionSet(1, array(
      'agent' => $agent->machine_name,
      'plugin' => 'type1',
      'num_options' => 3,
      'option_ids' => array(
        'option-A',
        'option-B',
        'option-C',
      ),
    ));
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/targeting');

    // There is no test created yet so there should be no way to pick a winner.
    $this
      ->assertNoFieldById('acquia-lift-complete-everyone-else');

    // Create an audience
    $this
      ->drupalPostAJAX(NULL, array(), $this->addTargetAudienceElement);
    $edit = array(
      'audiences[new][0][details][name]' => 'Muppet fans',
      'audiences[new][0][details][mapping][contexts][0][context]' => 'user_profile_context' . PERSONALIZE_TARGETING_ADMIN_SEPARATOR . $context_1,
      'audiences[new][0][details][mapping][contexts][0][value][match]' => 'some value',
      'audiences[new][0][details][mapping][contexts][0][value][operator]' => 'equals',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $agent->machine_name,
      'step' => 'targeting',
    )));

    // Assign variations and verify that there is still no way to pick a winner.
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/targeting');
    $edit = array(
      'audiences[existing][muppet-fans][assignment_order]' => 'option-A',
      'audiences[existing][everyone-else][assignment_order]' => 'option-B,option-C',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $agent->machine_name,
      'step' => 'targeting',
    )));
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/targeting');
    $this
      ->assertNoFieldById('acquia-lift-complete-everyone-else');
    $this
      ->assertNoFieldById('acquia-lift-complete-muppet-fans');

    // Start the agent and verify that the button is available for the test.
    $this
      ->drupalPost('admin/structure/personalize/manage/' . $agent->machine_name . '/review', array(), $this
      ->getButton('wizard_start'));
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/targeting');
    $this
      ->assertFieldById('acquia-lift-complete-everyone-else');
    $this
      ->assertNoFieldById('acquia-lift-complete-muppet-fans');

    // Pause the agent and the button is still available.
    personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_PAUSED);
    $this
      ->resetAll();
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/targeting');
    $this
      ->assertFieldById('acquia-lift-complete-everyone-else');
    $this
      ->assertNoFieldById('acquia-lift-complete-muppet-fans');

    // Adjust the assignments to convert the targeting audience to a test
    // and verify that it still does not have a winner selection button.
    $edit = array(
      'audiences[existing][muppet-fans][assignment_order]' => 'option-A,option-B',
      'audiences[existing][everyone-else][assignment_order]' => 'option-B,option-C',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $agent->machine_name,
      'step' => 'targeting',
    )));
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/targeting');
    $this
      ->assertFieldById('acquia-lift-complete-everyone-else');
    $this
      ->assertNoFieldById('acquia-lift-complete-muppet-fans');

    // Start the agent and now there should be buttons for both audiences.
    $this
      ->drupalPost('admin/structure/personalize/manage/' . $agent->machine_name . '/review', array(), $this
      ->getButton('wizard_start'));
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/targeting');
    $this
      ->assertFieldById('acquia-lift-complete-everyone-else');
    $this
      ->assertFieldById('acquia-lift-complete-muppet-fans-2');

    // Pause the test again and convert a test to pure targeting.
    personalize_agent_set_status($agent->machine_name, PERSONALIZE_STATUS_PAUSED);
    $this
      ->resetAll();
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/targeting');
    $this
      ->assertFieldById('acquia-lift-complete-everyone-else');
    $this
      ->assertFieldById('acquia-lift-complete-muppet-fans-2');
    $edit = array(
      'audiences[existing][muppet-fans-2][assignment_order]' => 'option-A,option-B',
      'audiences[existing][everyone-else][assignment_order]' => 'option-C',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $agent->machine_name,
      'step' => 'targeting',
    )));
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/targeting');
    $this
      ->assertNoFieldById('acquia-lift-complete-everyone-else');
    $this
      ->assertFieldById('acquia-lift-complete-muppet-fans-2');

    // Start the test again and confirm options remain the same.
    $this
      ->drupalPost('admin/structure/personalize/manage/' . $agent->machine_name . '/review', array(), $this
      ->getButton('wizard_start'));
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/targeting');
    $this
      ->assertNoFieldById('acquia-lift-complete-everyone-else');
    $this
      ->assertFieldById('acquia-lift-complete-muppet-fans-2');
  }

  /**
   * Test the advanced test settings on the targeting page.
   */
  function testAdvancedTestSettings() {

    // Enable a context to enable the targeting page.
    module_enable(array(
      'personalize_url_context',
    ));
    $this
      ->resetAll();
    $this
      ->resetAll();
    $this
      ->drupalLogin($this->managerUser);
    $agent = $this
      ->createTargetingAgent();
    $option_set = $this
      ->createOptionSet(1, array(
      'agent' => $agent->machine_name,
      'plugin' => 'type1',
      'num_options' => 2,
      'option_ids' => array(
        'option-1',
        'option-2',
      ),
    ));
    $this
      ->createTestFromOptionSet($agent, $option_set);
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/targeting');

    // Make some changes to the test settings and confirm that they save.
    $edit = array(
      'control_rate' => 30,
      'explore_rate' => 40,
      'decision_style' => 'adaptive',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $agent->machine_name,
      'step' => 'targeting',
    )));
    $agent = personalize_agent_load($agent->machine_name, TRUE);
    $this
      ->assertEqual($agent->data['control_rate'], 30);
    $this
      ->assertEqual($agent->data['explore_rate'], 40);
    $this
      ->assertEqual($agent->data['decision_style'], 'adaptive');

    // Now remove any tests and ensure that test settings can't be changed.
    $edit = array(
      'control_rate' => 10,
      'explore_rate' => 10,
      'decision_style' => 'random',
      'audiences[existing][everyone-else][assignment_order]' => 'option-1',
    );
    $this
      ->drupalPost('admin/structure/personalize/manage/' . $agent->machine_name . '/targeting', $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $agent->machine_name,
      'step' => 'targeting',
    )));

    // The test options should not have changed because they would have been
    // hidden.
    $agent = personalize_agent_load($agent->machine_name, TRUE);
    $this
      ->assertEqual($agent->data['control_rate'], 30);
    $this
      ->assertEqual($agent->data['explore_rate'], 40);
    $this
      ->assertEqual($agent->data['decision_style'], 'adaptive');
  }

}
class AcquiaLiftWebTestCampaignWizard extends AcquiaLiftWebTestCampaignWizardBase {
  public static function getInfo() {
    return array(
      'name' => t('Acquia Lift Web Tests - Personalization Wizard Goals'),
      'description' => t('Tests functionality related to the personalization management wizard goals forms.'),
      'group' => t('Personalize'),
    );
  }

  /**
   * Test goals type form.
   */
  function testGoalTypeSelect() {
    $goal_input_name = key($this->addGoalElement);
    $goal_input_value = reset($this->addGoalElement);
    $existing_action = 'goals[new][0][details][action_name]';
    $page_event = 'goals[new][0][details][event][page]';
    $element_url = 'goals[new][0][details][url]';
    $goal_type_name = 'goals[new][0][goal_type]';
    $cancel_element = array(
      'cancel_goal_0' => t('Cancel'),
    );
    $agent = $this
      ->createTargetingAgent();
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/goals');

    // Only a button to add a new goal shown by default
    $this
      ->assertFieldByName($goal_input_name, $goal_input_value);
    $this
      ->assertNoFieldByName($goal_type_name);
    $this
      ->assertNoFieldByName($existing_action);
    $this
      ->assertNoFieldByName($page_event);
    $this
      ->assertNoFieldByname($element_url);
    $this
      ->drupalPostAJAX(NULL, array(), $this->addGoalElement);

    // Make sure the type selection is shown by default without any selections.
    $this
      ->assertFieldByName($goal_type_name);
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-existing');
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-page');
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-element');

    // Actual forms should not be shown yet.
    $this
      ->assertNoFieldByName($existing_action);
    $this
      ->assertNoFieldByName($page_event);
    $this
      ->assertNoFieldByname($element_url);

    // Button to add a new goal should still be available.
    $this
      ->assertFieldByName($goal_input_name, $goal_input_value);

    // Cancel goal creation.
    $this
      ->drupalPostAJAX(NULL, array(), $cancel_element);
    $this
      ->assertFieldByName($goal_input_name, $goal_input_value);
    $this
      ->assertNoFieldByName($goal_type_name);
    $this
      ->assertNoFieldByName($existing_action);
    $this
      ->assertNoFieldByName($page_event);
    $this
      ->assertNoFieldByname($element_url);

    // Select an existing goal.
    $this
      ->drupalPostAJAX(NULL, array(), $this->addGoalElement);
    $this
      ->assertFieldByName($goal_type_name);
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-existing');
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-page');
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-element');
    $this
      ->assertNoFieldByName($existing_action);
    $this
      ->assertNoFieldByName($page_event);
    $this
      ->assertNoFieldByname($element_url);
    $this
      ->assertFieldByName($goal_input_name, $goal_input_value);
    $edit = array(
      $goal_type_name => 'existing',
    );
    $this
      ->drupalPostAJAX(NULL, $edit, $goal_type_name);
    $this
      ->assertFieldByName($goal_input_name, $goal_input_value);
    $this
      ->assertNoFieldByName($goal_type_name);
    $this
      ->assertFieldByName($existing_action);
    $this
      ->assertNoFieldByName($page_event);
    $this
      ->assertNoFieldByname($element_url);

    // Change the type
    $this
      ->drupalPostAJAX(NULL, array(), $this->changeTypeElement);
    $this
      ->assertFieldByName($goal_type_name);
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-existing');
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-page');
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-element');
    $this
      ->assertNoFieldByName($existing_action);
    $this
      ->assertNoFieldByName($page_event);
    $this
      ->assertNoFieldByname($element_url);
    $this
      ->assertFieldByName($goal_input_name, $goal_input_value);

    // Select existing again.
    $edit = array(
      $goal_type_name => 'existing',
    );
    $this
      ->drupalPostAJAX(NULL, $edit, $goal_type_name);
    $this
      ->assertFieldByName($goal_input_name, $goal_input_value);
    $this
      ->assertNoFieldByName($goal_type_name);
    $this
      ->assertFieldByName($existing_action);
    $this
      ->assertNoFieldByName($page_event);
    $this
      ->assertNoFieldByname($element_url);

    // Cancel the creation of the goal.
    $this
      ->drupalPostAJAX(NULL, array(), $cancel_element);
    $this
      ->assertFieldByName($goal_input_name, $goal_input_value);
    $this
      ->assertNoFieldByName($goal_type_name);
    $this
      ->assertNoFieldByName($existing_action);
    $this
      ->assertNoFieldByName($page_event);
    $this
      ->assertNoFieldByname($element_url);

    // Select a page goal
    $this
      ->drupalPostAJAX(NULL, array(), $this->addGoalElement);
    $this
      ->assertFieldByName($goal_type_name);
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-existing');
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-page');
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-element');
    $this
      ->assertNoFieldByName($existing_action);
    $this
      ->assertNoFieldByName($page_event);
    $this
      ->assertNoFieldByname($element_url);
    $this
      ->assertFieldByName($goal_input_name, $goal_input_value);
    $edit = array(
      $goal_type_name => 'page',
    );
    $this
      ->drupalPostAJAX(NULL, $edit, $goal_type_name);
    $this
      ->assertFieldByName($goal_input_name, $goal_input_value);
    $this
      ->assertNoFieldByName($goal_type_name);
    $this
      ->assertNoFieldByName($existing_action);
    $this
      ->assertFieldByName($page_event);
    $this
      ->assertNoFieldByname($element_url);

    // Change the type
    $this
      ->drupalPostAJAX(NULL, array(), $this->changeTypeElement);
    $this
      ->assertFieldByName($goal_type_name);
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-existing');
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-page');
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-element');
    $this
      ->assertNoFieldByName($existing_action);
    $this
      ->assertNoFieldByName($page_event);
    $this
      ->assertNoFieldByname($element_url);
    $this
      ->assertFieldByName($goal_input_name, $goal_input_value);

    // Select page again.
    $edit = array(
      $goal_type_name => 'page',
    );
    $this
      ->drupalPostAJAX(NULL, $edit, $goal_type_name);
    $this
      ->assertFieldByName($goal_input_name, $goal_input_value);
    $this
      ->assertNoFieldByName($goal_type_name);
    $this
      ->assertNoFieldByName($existing_action);
    $this
      ->assertFieldByName($page_event);
    $this
      ->assertNoFieldByname($element_url);

    // Cancel the creation of the goal.
    $this
      ->drupalPostAJAX(NULL, array(), $cancel_element);
    $this
      ->assertFieldByName($goal_input_name, $goal_input_value);
    $this
      ->assertNoFieldByName($goal_type_name);
    $this
      ->assertNoFieldByName($existing_action);
    $this
      ->assertNoFieldByName($page_event);
    $this
      ->assertNoFieldByname($element_url);

    // Select an element goal.
    $this
      ->drupalPostAJAX(NULL, array(), $this->addGoalElement);
    $this
      ->assertFieldByName($goal_type_name);
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-existing');
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-page');
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-element');
    $this
      ->assertNoFieldByName($existing_action);
    $this
      ->assertNoFieldByName($page_event);
    $this
      ->assertNoFieldByname($element_url);
    $this
      ->assertFieldByName($goal_input_name, $goal_input_value);
    $edit = array(
      $goal_type_name => 'element',
    );
    $this
      ->drupalPostAJAX(NULL, $edit, $goal_type_name);
    $this
      ->assertFieldByName($goal_input_name, $goal_input_value);
    $this
      ->assertNoFieldByName($goal_type_name);
    $this
      ->assertNoFieldByName($existing_action);
    $this
      ->assertNoFieldByName($page_event);
    $this
      ->assertFieldByname($element_url);

    // Change the type
    $this
      ->drupalPostAJAX(NULL, array(), $this->changeTypeElement);
    $this
      ->assertFieldByName($goal_type_name);
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-existing');
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-page');
    $this
      ->assertNoFieldChecked('edit-goals-new-0-goal-type-element');
    $this
      ->assertNoFieldByName($existing_action);
    $this
      ->assertNoFieldByName($page_event);
    $this
      ->assertNoFieldByname($element_url);
    $this
      ->assertFieldByName($goal_input_name, $goal_input_value);

    // Select existing again.
    $edit = array(
      $goal_type_name => 'element',
    );
    $this
      ->drupalPostAJAX(NULL, $edit, $goal_type_name);
    $this
      ->assertFieldByName($goal_input_name, $goal_input_value);
    $this
      ->assertNoFieldByName($goal_type_name);
    $this
      ->assertNoFieldByName($existing_action);
    $this
      ->assertNoFieldByName($page_event);
    $this
      ->assertFieldByname($element_url);

    // Cancel the creation of the goal.
    $this
      ->drupalPostAJAX(NULL, array(), $cancel_element);
    $this
      ->assertFieldByName($goal_input_name, $goal_input_value);
    $this
      ->assertNoFieldByName($goal_type_name);
    $this
      ->assertNoFieldByName($existing_action);
    $this
      ->assertNoFieldByName($page_event);
    $this
      ->assertNoFieldByname($element_url);
  }

  /**
   * Test goals form.
   */
  function testGoals() {
    $goal_input_name = key($this->addGoalElement);
    $goal_input_value = reset($this->addGoalElement);
    $goal_type_name = 'goals[new][0][goal_type]';
    $this
      ->drupalLogin($this->managerUser);
    $agent = $this
      ->createTargetingAgent();
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/goals');
    $this
      ->assertNoText('Goals cannot be changed while the personalization is running.');

    // Check existing form.
    $this
      ->drupalPostAJAX(NULL, array(), $this->addGoalElement);
    $edit = array(
      $goal_type_name => 'existing',
    );
    $this
      ->drupalPostAJAX(NULL, $edit, $goal_type_name);

    // Add an existing goal.
    $edit = array(
      'goals[new][0][details][action_name]' => 'user_login',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_save'));

    // Note that new goals are looped through with array indexes rather than
    // by goal IDs so we can assume the values will be consecutive.
    $this
      ->assertOptionSelected('edit-goals-all-goals-0-action-name', 'user_login');
    $this
      ->assertFieldByName('goals[all_goals][0][value]', 1);

    // Add a page goal.
    $this
      ->drupalPostAJAX(NULL, array(), $this->addGoalElement);
    $edit = array(
      $goal_type_name => 'page',
    );
    $this
      ->drupalPostAJAX(NULL, $edit, $goal_type_name);
    $edit = array(
      'goals[new][0][details][title]' => 'Test goal',
      'goals[new][0][details][event][page]' => 'client::scrollToBottom',
      'goals[new][0][details][pages]' => 'node',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_save'));
    $this
      ->assertOptionSelected('edit-goals-all-goals-1-action-name', 'test_goal');
    $this
      ->assertFieldByName('goals[all_goals][1][value]', 1);

    // Edit the new goal to an invalid action.
    $edit = array(
      'goals[all_goals][1][action_name]' => 'user_login',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_save'));
    $this
      ->assertText('Actions can only be used once per personalization.');

    // Edit the goal with valid values.
    $edit = array(
      'goals[all_goals][1][action_name]' => 'form_submit',
      'goals[all_goals][1][value]' => 5,
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_save'));

    // Verify everything is as expected.
    $this
      ->assertFieldByName($goal_input_name, $goal_input_value);
    $this
      ->assertOptionSelected('edit-goals-all-goals-0-action-name', 'user_login');
    $this
      ->assertFieldByName('goals[all_goals][0][value]', 1);
    $this
      ->assertOptionSelected('edit-goals-all-goals-1-action-name', 'form_submit');
    $this
      ->assertFieldByName('goals[all_goals][1][value]', 5);

    // Make sure all goals saved as expected too.
    $this
      ->resetAll();
    $goal_entities = personalize_goal_load_by_conditions(array(
      'agent' => $agent->machine_name,
    ));
    $test_goals = array_values($goal_entities);
    $this
      ->assertEqual(count($test_goals), 2);
    $this
      ->assertEqual($test_goals[0]->action, 'user_login');
    $this
      ->assertEqual($test_goals[0]->value, 1);
    $this
      ->assertEqual($test_goals[1]->action, 'form_submit');
    $this
      ->assertEqual($test_goals[1]->value, 5);
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_save'));

    // Check elements form.
    $this
      ->drupalPostAJAX(NULL, array(), $this->addGoalElement);
    $edit = array(
      $goal_type_name => 'element',
    );
    $this
      ->drupalPostAJAX(NULL, $edit, $goal_type_name);
    $edit = array(
      'goals[new][0][details][url]' => 'node',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_element_navigate'));
    $this
      ->assertNoText('You have specified an invalid path');
    $this
      ->assertUrl('node');
  }

}
class AcquiaLiftWebTestCampaignWizardReview extends AcquiaLiftWebTestCampaignWizardBase {
  public static function getInfo() {
    return array(
      'name' => t('Acquia Lift Web Tests - Personalization Wizard - Review'),
      'description' => t('Tests functionality related to the personalization management wizard review and status.'),
      'group' => t('Personalize'),
    );
  }

  /**
   * Tests the submission of the review form which results in nested tests
   * being created.
   */
  function testReviewSubmit() {

    // Provide context options to enable targeting page.
    module_enable(array(
      'personalize_url_context',
    ));
    $this
      ->resetAll();
    $this
      ->resetAll();
    $parent_settings = array(
      'control_rate' => 20,
      'explore_rate' => 40,
      'decision_style' => 'random',
      'cache_decisions' => 0,
    );
    $agent = $this
      ->createTargetingAgent($this
      ->randomName(), $parent_settings);
    $option_set = $this
      ->createOptionSet(1, array(
      'agent' => $agent->machine_name,
      'plugin' => 'type1',
      'num_options' => 2,
    ));

    // Add the new options to a test.
    $this
      ->createTestFromOptionSet($agent, $option_set);

    // Start the agent.
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/review');
    $this
      ->assertNoText(t('Next steps'));
    $this
      ->drupalPost(NULL, array(), $this
      ->getButton('wizard_start'));

    // Confirm message and next steps block.
    $this
      ->assertText(t('Congratulations! You have started your personalization.'));
    $this
      ->assertText(t('Need help?'));

    // Confirm settings are propagated.
    $this
      ->resetAll();
    $agent = personalize_agent_load($agent->machine_name, TRUE);
    $status = personalize_agent_get_status($agent->machine_name);
    $this
      ->assertEqual($status, PERSONALIZE_STATUS_RUNNING);
    foreach ($parent_settings as $setting => $value) {
      $this
        ->assertEqual($agent->data[$setting], $value);
    }
    $nested_tests = acquia_lift_get_nested_tests($agent);
    $nested_settings = $parent_settings;

    // The cache_decisions setting should be 1 instead of 0.
    $nested_settings['cache_decisions'] = 1;

    // Explore rate should be set to 1;
    $nested_settings['explore_rate'] = 100;
    $nested1 = personalize_agent_load($nested_tests[0]);
    foreach ($nested_settings as $setting => $value) {
      $this
        ->assertEqual($nested1->data[$setting], $value);
    }
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/review');
    module_load_include('inc', 'acquia_lift', 'acquia_lift.admin');
    acquia_lift_target_set_status($agent, PERSONALIZE_STATUS_PAUSED);
    $this
      ->resetAll();
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/review');

    // Confirm that the next steps still show even after pausing.
    $this
      ->assertText(t('Need help?'));
    $changes = array(
      'control_rate' => 30,
      'explore_rate' => 60,
      'decision_style' => 'adaptive',
    );
    $this
      ->drupalPost('admin/structure/personalize/manage/' . $agent->machine_name . '/targeting', $changes, $this
      ->getButton('wizard_next', array(
      'agent_name' => $agent->machine_name,
      'step' => 'targeting',
    )));
    $this
      ->drupalPost('admin/structure/personalize/manage/' . $agent->machine_name . '/review', array(), $this
      ->getButton('wizard_start'));
    $this
      ->assertText(t('Congratulations! You have started your personalization.'));
    $this
      ->assertText(t('Need help?'));
    $this
      ->resetAll();
    $agent = personalize_agent_load($agent->machine_name, TRUE);

    // Confirm the changes propagated to the nested test.
    $parent_settings['control_rate'] = $nested_settings['control_rate'] = 30;
    $parent_settings = array_merge($parent_settings, $changes);
    $nested_settings = array_merge($nested_settings, $changes);
    $this
      ->assertEqual($agent->data['control_rate'], $parent_settings['control_rate']);
    $this
      ->assertEqual($agent->data['explore_rate'], $parent_settings['explore_rate']);
    $this
      ->assertEqual($agent->data['explore_rate'], $parent_settings['explore_rate']);
    $nested1 = personalize_agent_load($nested1->machine_name, TRUE);
    foreach ($nested_settings as $setting => $value) {
      $this
        ->assertEqual($nested1->data[$setting], $value);
    }
  }

  /**
   * Tests the review submission for a targeting only test.
   */
  function testReviewSubmitTargeting() {
    $agent = $this
      ->createTargetingAgent();
    $option_set = $this
      ->createOptionSet(1, array(
      'agent' => $agent->machine_name,
      'plugin' => 'plugin_type',
      'num_options' => 2,
    ));
    $option_id_1 = $option_set->options[0]['option_id'];
    $option_id_2 = $option_set->options[1]['option_id'];

    // Create user profile fields that we can use for targeting.
    $user_profile_field_1 = $this
      ->createUserProfileField();
    $context_1 = str_replace('field_', '', $user_profile_field_1['field_name']);

    // Create an audience for targeting.
    $this
      ->drupalGet('admin/structure/personalize/manage/' . $agent->machine_name . '/targeting');
    $this
      ->drupalPostAJAX(NULL, array(), $this->addTargetAudienceElement);
    $edit = array(
      'audiences[new][0][details][name]' => 'Muppet fans',
      'audiences[new][0][details][mapping][contexts][0][context]' => 'user_profile_context' . PERSONALIZE_TARGETING_ADMIN_SEPARATOR . $context_1,
      'audiences[new][0][details][mapping][contexts][0][value][match]' => 'some value',
      'audiences[new][0][details][mapping][contexts][0][value][operator]' => 'equals',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_save'));

    // Assign variations to audiences.
    $edit = array(
      'audiences[existing][muppet-fans][assignment_order]' => $option_id_1,
      'audiences[existing][everyone-else][assignment_order]' => $option_id_2,
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $agent->machine_name,
      'step' => 'targeting',
    )));

    // Now start the campaign from the review screen.
    $this
      ->drupalPost(NULL, array(), $this
      ->getButton('wizard_start'));
    $this
      ->resetAll();

    // Confirm that the campaign was started
    $this
      ->assertEqual(personalize_agent_get_status($agent->machine_name), PERSONALIZE_STATUS_RUNNING);
  }

  /**
   * Tests the behavior of the review form when there are batch sync errors.
   */
  function testReviewSubmitErrors() {
    $agent = $this
      ->createTargetingAgent();
    $option_set = $this
      ->createOptionSet(1, array(
      'agent' => $agent->machine_name,
      'plugin' => 'type1',
      'num_options' => 2,
    ));

    // Try to start the agent.
    $this
      ->drupalPost('admin/structure/personalize/manage/' . $agent->machine_name . '/review', array(), $this
      ->getButton('wizard_start'));
    $this
      ->assertText('There is a problem with this personalization and it cannot be run at this time');
    $this
      ->assertText('You have not assigned any variations to audiences');

    // Confirm the agent's status has not changed.
    personalize_agent_load($agent->machine_name, TRUE);
    $status = personalize_agent_get_status($agent->machine_name);
    $this
      ->assertEqual($status, PERSONALIZE_STATUS_NOT_STARTED);

    // Add targeting so it will no longer fail for this reason.
    $this
      ->createTestFromOptionSet($agent, $option_set);

    // Cause batch syncing to fail by using a broken http client.
    variable_set('acquia_lift_web_test_broken_client', TRUE);
    $this
      ->resetAll();
    $this
      ->drupalPost('admin/structure/personalize/manage/' . $agent->machine_name . '/review', array(), $this
      ->getButton('wizard_start'));

    // Confirm the agent's status still has not changed.
    personalize_agent_load($agent->machine_name, TRUE);
    $status = personalize_agent_get_status($agent->machine_name);
    $this
      ->assertEqual($status, PERSONALIZE_STATUS_NOT_STARTED);

    // @todo Figure out a way to test a failure that happens *during* batch -
    //   the above failure happens before the batch even starts because an
    //   exception is thrown when trying to get the operations.
  }

  /**
   * Tests review form status changes.
   */
  function testReviewFormStatus() {
    $message_running = t('Personalizations that are running cannot be edited. Click "Pause" to allow it to be edited. Personalizations that are paused display the default variations to visitors.');
    $message_scheduled = t('Personalizations with scheduled start dates cannot be edited.  Click "Make editable" to allow it to be edited. After you have made your changes, go to the Review section to restart the personalization.');
    $message_completed = t('Archived personalizations cannot be edited.  Click "Unarchive" for the personalization to restore it to a Paused status, allowing it to be edited.');
    $this
      ->drupalLogin($this->managerUser);
    $agent = $this
      ->createTargetingAgent();
    $machine_name = $agent->machine_name;
    $campaign_pages = array(
      "admin/structure/personalize/manage/{$machine_name}/variations",
      "admin/structure/personalize/manage/{$machine_name}/goals",
      "admin/structure/personalize/manage/{$machine_name}/targeting",
      "admin/structure/personalize/manage/{$machine_name}/scheduling",
      "admin/structure/personalize/manage/{$machine_name}/review",
    );

    // Add option set.
    $option_set = $this
      ->createPersonalizedBlock(0, $agent);

    // Create a test.
    $this
      ->createTestFromOptionSet($agent, $option_set);

    // Schedule the campaign to start in the future.
    $this
      ->drupalGet("admin/structure/personalize/manage/{$machine_name}/scheduling");
    $start_date = strtotime('+1 month midnight');
    $edit = array(
      'campaign_start' => 'specified',
      'campaign_start_date[month]' => intval(date('m', $start_date)),
      'campaign_start_date[day]' => date('d', $start_date),
      'campaign_start_date[year]' => date('Y', $start_date),
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $machine_name,
      'step' => 'scheduling',
    )));

    // Verify options.
    foreach ($campaign_pages as $page) {
      $this
        ->drupalGet($page);
      $this
        ->assertNoText($message_running);
      $this
        ->assertNoText($message_scheduled);
      $this
        ->assertNoText($message_completed);
      $this
        ->assertFieldById('edit-save');
      $this
        ->assertFieldById('edit-submit-' . PERSONALIZE_STATUS_RUNNING);
      $this
        ->assertNoFieldById('edit-submit-' . PERSONALIZE_STATUS_PAUSED);
      $this
        ->assertNoFieldById('edit-submit-' . PERSONALIZE_STATUS_COMPLETED);
      $this
        ->assertFieldById('edit-submit-' . PERSONALIZE_STATUS_SCHEDULED);
    }

    // Remove the scheduled date prior to starting the campaign.
    $this
      ->drupalGet("admin/structure/personalize/manage/{$machine_name}/scheduling");
    $edit = array(
      'campaign_start' => 'none',
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $machine_name,
      'step' => 'scheduling',
    )));

    // Verify options.
    foreach ($campaign_pages as $page) {
      $this
        ->drupalGet($page);
      $this
        ->assertNoText($message_running);
      $this
        ->assertNoText($message_scheduled);
      $this
        ->assertNoText($message_completed);
      $this
        ->assertFieldById('edit-save');
      $this
        ->assertFieldById('edit-submit-' . PERSONALIZE_STATUS_RUNNING);
      $this
        ->assertNoFieldById('edit-submit-' . PERSONALIZE_STATUS_PAUSED);
      $this
        ->assertNoFieldById('edit-submit-' . PERSONALIZE_STATUS_COMPLETED);
      $this
        ->assertNoFieldById('edit-submit-' . PERSONALIZE_STATUS_SCHEDULED);
    }

    // Start the campaign.
    $this
      ->drupalGet("admin/structure/personalize/manage/{$machine_name}/review");
    $this
      ->drupalPost(NULL, array(), $this
      ->getButton('wizard_start'));
    $this
      ->assertText(t('Congratulations! You have started your personalization.'));

    // Verify that the correct messaging is shown on all campaign wizard pages.
    foreach ($campaign_pages as $page) {
      $this
        ->drupalGet($page);
      $this
        ->assertText($message_running);
      $this
        ->assertNoText($message_scheduled);
      $this
        ->assertNoText($message_completed);
      $this
        ->assertNoFieldById('edit-save');
      $this
        ->assertNoFieldById('edit-submit-' . PERSONALIZE_STATUS_RUNNING);
      $this
        ->assertNoFieldById('edit-submit-' . PERSONALIZE_STATUS_PAUSED);
      $this
        ->assertNoFieldById('edit-submit-' . PERSONALIZE_STATUS_COMPLETED);
      $this
        ->assertNoFieldById('edit-submit-' . PERSONALIZE_STATUS_SCHEDULED);
    }

    // Pause the campaign and verify that messaging is removed.
    $this
      ->drupalPost(NULL, array(), t('Pause'));
    $this
      ->assertNoText(t('Congratulations! You have started your personalization.'));
    foreach ($campaign_pages as $page) {
      $this
        ->drupalGet($page);
      $this
        ->assertNoText($message_running);
      $this
        ->assertNoText($message_scheduled);
      $this
        ->assertNoText($message_completed);
      $this
        ->assertFieldById('edit-save');
      $this
        ->assertFieldById('edit-submit-' . PERSONALIZE_STATUS_RUNNING);
      $this
        ->assertNoFieldById('edit-submit-' . PERSONALIZE_STATUS_PAUSED);
      $this
        ->assertFieldById('edit-submit-' . PERSONALIZE_STATUS_COMPLETED);
      $this
        ->assertNoFieldById('edit-submit-' . PERSONALIZE_STATUS_SCHEDULED);
    }

    // Schedule the campaign to start in the future.
    $this
      ->drupalGet("admin/structure/personalize/manage/{$machine_name}/scheduling");
    $start_date = strtotime('+1 month midnight');
    $edit = array(
      'campaign_start' => 'specified',
      'campaign_start_date[month]' => intval(date('m', $start_date)),
      'campaign_start_date[day]' => date('d', $start_date),
      'campaign_start_date[year]' => date('Y', $start_date),
    );
    $this
      ->drupalPost(NULL, $edit, $this
      ->getButton('wizard_next', array(
      'agent_name' => $machine_name,
      'step' => 'scheduling',
    )));

    // Verify that the correct messaging is shown on all campaign wizard pages.
    foreach ($campaign_pages as $page) {
      $this
        ->drupalGet($page);
      $this
        ->assertNoText($message_running);
      $this
        ->assertNoText($message_scheduled);
      $this
        ->assertNoText($message_completed);
      $this
        ->assertFieldById('edit-save');
      $this
        ->assertFieldById('edit-submit-' . PERSONALIZE_STATUS_RUNNING);
      $this
        ->assertNoFieldById('edit-submit-' . PERSONALIZE_STATUS_PAUSED);
      $this
        ->assertFieldById('edit-submit-' . PERSONALIZE_STATUS_COMPLETED);
      $this
        ->assertFieldById('edit-submit-' . PERSONALIZE_STATUS_SCHEDULED);
    }

    // Actually schedule the campaign.
    module_load_include('inc', 'personalize', 'personalize.admin.campaign');
    $button_text = t('Start on @start_date', array(
      '@start_date' => _personalize_campaign_wizard_date($start_date),
    ));
    $this
      ->drupalPost(NULL, array(), $button_text);
    $this
      ->assertText(t('Congratulations!  You have scheduled your personalization to start on @date', array(
      '@date' => _personalize_campaign_wizard_date($start_date),
    )));

    // Verify that the correct messaging is shown on all campaign wizard pages.
    foreach ($campaign_pages as $page) {
      $this
        ->drupalGet($page);
      $this
        ->assertNoText($message_running);
      $this
        ->assertText($message_scheduled);
      $this
        ->assertNoText($message_completed);
      $this
        ->assertNoFieldById('edit-save');
      $this
        ->assertNoFieldById('edit-submit-' . PERSONALIZE_STATUS_RUNNING);
      $this
        ->assertNoFieldById('edit-submit-' . PERSONALIZE_STATUS_PAUSED);
      $this
        ->assertNoFieldById('edit-submit-' . PERSONALIZE_STATUS_COMPLETED);
      $this
        ->assertNoFieldById('edit-submit-' . PERSONALIZE_STATUS_SCHEDULED);
    }

    // Complete the campaign and verify messaging.
    personalize_agent_set_status($machine_name, PERSONALIZE_STATUS_COMPLETED);
    $this
      ->resetAll();
    foreach ($campaign_pages as $page) {
      $this
        ->drupalGet($page);
      $this
        ->assertNoText('Congratulations!');
      $this
        ->assertNoText($message_running);
      $this
        ->assertNoText($message_scheduled);
      $this
        ->assertText($message_completed);
      $this
        ->assertNoFieldById('edit-save');
      $this
        ->assertNoFieldById('edit-submit-' . PERSONALIZE_STATUS_RUNNING);
      $this
        ->assertNoFieldById('edit-submit-' . PERSONALIZE_STATUS_PAUSED);
      $this
        ->assertNoFieldById('edit-submit-' . PERSONALIZE_STATUS_COMPLETED);
      $this
        ->assertNoFieldById('edit-submit-' . PERSONALIZE_STATUS_SCHEDULED);
    }
  }

}