acquia_lift.test in Acquia Lift Connector 7
Same filename and directory in other branches
Integration tests for Acquia Lift module.
File
tests/acquia_lift.testView source
<?php
/**
* @file
* Integration tests for Acquia Lift module.
*/
class AcquiaLiftWebTestBase extends DrupalWebTestCase {
/**
* The string to use as the runtime API key.
*
* @var string
*/
protected $liftAPIKey = 'api-key-123';
/**
* The string to use as the admin API key.
*
* @var string
*/
protected $liftAdminKey = 'admin-key-123';
/**
* The string to use as the admin API URL.
*
* @var string
*/
protected $liftAPIUrl = 'http://some.valid.url';
/**
* The string to use as the owner code.
*
* @var string
*/
protected $liftAOwnerCode = 'Some_valid-owner123-code';
protected $adminUser;
protected $managerUser;
protected $personalizedQueue;
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',
'personalize_test',
));
$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
->drupalLogin($this->managerUser);
$this->personalizedQueue = DrupalQueue::get('acquia_lift_sync');
variable_set('acquia_lift_account_info', array(
'owner_code' => $this->liftAOwnerCode,
'api_key' => $this->liftAPIKey,
'admin_key' => $this->liftAdminKey,
));
}
public function tearDown() {
variable_del('acquia_lift_web_test_data');
parent::tearDown();
}
/**
* Asserts that the expected items are in the queue.
*
* @param $expected_items
* An array of queued items.
*/
protected function assertQueueItems($expected_items) {
$actual_items = array();
$result = db_query('SELECT data FROM {queue} q WHERE name = \'acquia_lift_sync\' ORDER BY created ASC');
foreach ($result as $row) {
$actual_items[] = unserialize($row->data);
}
$this
->assertEqual($expected_items, $actual_items);
}
/**
* Help function to create and test queue creation of Personalize Agent
*
* @param array $data
* array (
* 'name' => Agent title
* 'machine_name' => string processed by personalize_generate_machine_name()
* )
* @param bool $cleanQueue Clean or not Drupal queue after 'saveAgent' queue testing
* @return NULL|PersonalizeAgentInterface
*
* @see personalize_generate_machine_name()
* @see testSaveAgent()
*/
protected function createTestAgent($data = array(), $cleanQueue = TRUE, $assertResults = TRUE) {
$this
->configureAcquiaLiftAccount();
$this
->drupalLogin($this->managerUser);
$data += array(
'name' => $this
->randomName(),
'agent_type' => 'acquia_lift',
'decision_style' => 'adaptive',
'control_rate' => 10,
'explore_rate' => 20,
'cache_decisions' => 1,
'auto_stop' => 0,
);
$data += array(
'machine_name' => personalize_generate_machine_name($data['name'], 'personalize_agent_machine_name_exists'),
);
$edit = array(
'agent_basic_info[title]' => $data['name'],
'agent_basic_info[machine_name]' => $data['machine_name'],
'agent_basic_info[agent_type]' => $data['agent_type'],
'agent_basic_info[options][acquia_lift][decision_style]' => $data['decision_style'],
'agent_basic_info[options][acquia_lift][control_rate]' => $data['control_rate'],
'agent_basic_info[options][acquia_lift][explore_rate]' => $data['explore_rate'],
'cache_decisions' => $data['cache_decisions'],
);
$this
->drupalPost('admin/structure/personalize/add', $edit, $this
->getButton('agent'));
if ($data['auto_stop']) {
$agent = personalize_agent_load($data['machine_name']);
$agent->data['auto_stop'] = 1;
AcquiaLiftAPI::setTestInstance();
personalize_agent_save($agent);
}
$agent = personalize_agent_load_agent($data['machine_name'], TRUE);
if ($assertResults) {
$this
->assertTrue($agent instanceof AcquiaLiftAgent);
}
$expected_queue_items = array(
array(
'method' => 'saveAgent',
'args' => array(
$data['machine_name'],
$data['name'],
'adaptive',
PERSONALIZE_STATUS_NOT_STARTED,
isset($data['control_rate']) ? $data['control_rate'] / 100 : 0.1,
isset($data['explore_rate']) ? $data['explore_rate'] / 100 : 0.2,
isset($data['cache_decisions']) && $data['cache_decisions'],
),
'agent' => $data['machine_name'],
),
);
if ($assertResults) {
$this
->assertQueueItems($expected_queue_items);
}
if ($cleanQueue) {
$this->personalizedQueue
->deleteQueue();
}
return $agent;
}
protected function createOptionSet($index, $optionData, $withQueueItems = TRUE) {
$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());
}
$expected_queue_items = array();
if ($withQueueItems) {
$expected_queue_items[] = array(
'method' => 'savePoint',
'args' => array(
$optionData['agent'],
personalize_get_decision_point_name_for_option_set($option_set),
),
'agent' => $optionData['agent'],
);
// An item will be added to the queue to save the decision.
$expected_queue_items[] = array(
'method' => 'saveDecision',
'args' => array(
$optionData['agent'],
personalize_get_decision_point_name_for_option_set($option_set),
personalize_get_decision_name_for_option_set($option_set),
),
'agent' => $optionData['agent'],
);
// An item will be added to teh queue to save each option.
foreach ($choice_ids as $choice) {
$expected_queue_items[] = array(
'method' => 'saveChoice',
'args' => array(
$optionData['agent'],
personalize_get_decision_point_name_for_option_set($option_set),
personalize_get_decision_name_for_option_set($option_set),
$choice,
),
'agent' => $optionData['agent'],
);
}
}
return array(
$option_set,
$expected_queue_items,
);
}
/**
* Creates a user profile field which can be used for targeting.
*
* @return array
* An associative array representing the field.
*/
protected function createUserProfileField() {
$field = array(
'field_name' => 'field_' . drupal_strtolower($this
->randomName()),
'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;
}
/**
* 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 = '') {
switch ($type) {
case 'agent':
return t('Save campaign settings');
case 'goal':
return t('Save goals');
case 'option':
return t('Save variation sets');
case 'mvt':
return t('Save test');
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() {
$edit = array(
'acquia_lift_account_info[owner_code]' => $this->liftAOwnerCode,
'acquia_lift_account_info[api_key]' => $this->liftAPIKey,
'acquia_lift_account_info[admin_key]' => $this->liftAdminKey,
'acquia_lift_account_info[api_url]' => $this->liftAPIUrl,
);
$this
->drupalLogin($this->adminUser);
$this
->drupalPost('admin/config/content/personalize/acquia_lift', $edit, $this
->getButton('config'));
$this
->resetAll();
}
/**
* 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', array(
'@num' => $i,
));
$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;
}
}
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 testLiftAgentAvailibility() {
// remove the account information
$lift_info = variable_get('acquia_lift_account_info', array());
variable_del('acquia_lift_account_info');
$this
->resetAll();
// Try to add a new campaign and verify that the Acquia Lift agent isn't presented.
$this
->drupalGet('admin/structure/personalize/add');
$this
->assertText(t('Your Acquia Lift account info has not been configured.'));
$this
->assertNoRaw('<option value="acquia_lift">acquia_lift</option>');
// Add the configuration information for the Lift account.
$this
->configureAcquiaLiftAccount();
$this
->drupalLogin($this->managerUser);
// Now confirm that Acquia Lift is an option for new campaigns.
$this
->drupalGet('admin/structure/personalize/add');
$this
->assertNoText(t('Your Acquia Lift account info has not been configured.'));
$this
->assertRaw('<option value="acquia_lift">acquia_lift</option>');
}
public function testConfigForm() {
$this
->drupalLogin($this->adminUser);
// Try entering an invalid owner code.
$edit = array(
'acquia_lift_account_info[owner_code]' => 'some invalid string',
'acquia_lift_account_info[api_key]' => $this->liftAPIKey,
'acquia_lift_account_info[admin_key]' => $this->liftAdminKey,
'acquia_lift_account_info[api_url]' => $this->liftAPIUrl,
);
$this
->drupalPost('admin/config/content/personalize/acquia_lift', $edit, $this
->getButton('config'));
$this
->assertText('You must enter a valid owner code');
// Now try with a valid code.
$edit['acquia_lift_account_info[owner_code]'] = $this->liftAOwnerCode;
$this
->drupalPost('admin/config/content/personalize/acquia_lift', $edit, $this
->getButton('config'));
$this
->assertNoText('You must enter a valid owner code');
$account_info = variable_get('acquia_lift_account_info', array());
$this
->assertEqual($account_info['owner_code'], $this->liftAOwnerCode);
$this
->assertEqual($account_info['api_key'], $this->liftAPIKey);
$this
->assertEqual($account_info['admin_key'], $this->liftAdminKey);
$this
->assertEqual($account_info['api_url'], 'some.valid.url');
// Try entering an invalid API url.
$edit['acquia_lift_account_info[api_url]'] = 'some\\invalid\\url';
$this
->drupalPost('admin/config/content/personalize/acquia_lift', $edit, $this
->getButton('config'));
$this
->assertText('You must enter a valid URL');
// Try a valid URL with no scheme.
$edit['acquia_lift_account_info[api_url]'] = 'some.valid.url';
$this
->drupalPost('admin/config/content/personalize/acquia_lift', $edit, $this
->getButton('config'));
$this
->assertNoText('You must enter a valid URL');
// Try a valid URL with scheme.
$edit['acquia_lift_account_info[api_url]'] = 'https://some.valid.url';
$this
->drupalPost('admin/config/content/personalize/acquia_lift', $edit, $this
->getButton('config'));
$this
->assertNoText('You must enter a valid URL');
$this
->resetAll();
$account_info = variable_get('acquia_lift_account_info', array());
// The scheme should have been stripped out before saving.
$this
->assertEqual($account_info['api_url'], 'some.valid.url');
// Submit bogus confidence measures.
$bad_measures = array(
'abcd' => t('Confidence measure must be a number.'),
145 => t('Confidence measure must be a value between 0 and 100.'),
-45 => t('Confidence measure must be a value between 0 and 100.'),
);
foreach ($bad_measures as $measure => $message) {
$edit['acquia_lift_confidence_measure'] = $measure;
$this
->drupalPost('admin/config/content/personalize/acquia_lift', $edit, $this
->getButton('config'));
$this
->assertText($message);
$this
->assertNoText(t('A minimum confidence measure of 80% is recommended to ensure proper evaluation of test results.'));
$this
->assertNoText(t('The configuration options have been saved.'));
}
// Submit a low confidence measure and test warning.
$edit['acquia_lift_confidence_measure'] = '10';
$this
->drupalPost('admin/config/content/personalize/acquia_lift', $edit, $this
->getButton('config'));
$this
->assertText(t('A minimum confidence measure of 95% is recommended to ensure proper evaluation of test results.'));
$this
->assertText(t('The configuration options have been saved.'));
// Submit a valid measure and confirm it is saved without warning.
$edit['acquia_lift_confidence_measure'] = '95';
$this
->drupalPost('admin/config/content/personalize/acquia_lift', $edit, $this
->getButton('config'));
$this
->assertNoText(t('A minimum confidence measure of 95% is recommended to ensure proper evaluation of test results.'));
$this
->assertText(t('The configuration options have been saved.'));
}
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 testPersonalizeElementsVariationSets() {
module_load_include('inc', 'acquia_lift', 'acquia_lift.page_variations');
$agent_name = 'test-agent';
// Variation 1 (only one element).
$os1 = personalize_elements_get_option_set_for_variation('my first os', $agent_name, 'div.some-class', 'addClass', 'node');
acquia_lift_page_variation_create('my_first_varset', $os1, array(
'personalize_elements_content' => 'test-class',
));
// Variation 2 (2 elements).
$os2 = personalize_elements_get_option_set_for_variation('my second os', $agent_name, 'div.some-class', 'appendHtml', 'node');
acquia_lift_page_variation_create('my_first_varset', $os2, array(
'personalize_elements_content' => 'appended html',
));
$os3 = personalize_elements_get_option_set_for_variation('my first os', $agent_name, 'div.some-class', 'addClass', 'node');
acquia_lift_page_variation_create('my_first_varset', $os3, array(
'personalize_elements_content' => 'other-class',
), 2);
$this
->resetAll();
$option_sets = personalize_option_set_load_multiple(FALSE, array(
'agent' => $agent_name,
));
$osids = array_keys($option_sets);
$this
->assertEqual(2, count($option_sets));
foreach ($option_sets as $osid => $option_set) {
$this
->assertEqual('my_first_varset', $option_set->decision_name);
$this
->assertEqual(3, count($option_set->options));
}
$expected_options_os1 = array(
array(
'option_id' => PERSONALIZE_CONTROL_OPTION_ID,
'option_label' => PERSONALIZE_CONTROL_OPTION_LABEL,
),
array(
'option_id' => 'variation-1',
'option_label' => 'Variation #1',
'personalize_elements_content' => 'test-class',
),
array(
'option_id' => 'variation-2',
'option_label' => 'Variation #2',
'personalize_elements_content' => 'other-class',
),
);
$this
->assertEqual($expected_options_os1, $option_sets[$osids[0]]->options);
$expected_options_os2 = array(
array(
'option_id' => PERSONALIZE_CONTROL_OPTION_ID,
'option_label' => PERSONALIZE_CONTROL_OPTION_LABEL,
),
array(
'option_id' => 'variation-1',
'option_label' => 'Variation #1',
),
array(
'option_id' => 'variation-2',
'option_label' => 'Variation #2',
'personalize_elements_content' => 'appended html',
),
);
$this
->assertEqual($expected_options_os2, $option_sets[$osids[1]]->options);
}
/**
* Tests variation set creation.
*
* A variation set can be made up of multiple option sets.
*
* @todo This should probably be combined with
* testPersonalizeElementsVariationSets() above and simplified to just
* personalize_elements elements (but with the complexity of this test).
*/
function testVariationSets() {
module_load_include('inc', 'acquia_lift', 'acquia_lift.page_variations');
$admin_user = $this
->drupalCreateUser(array(
'access administration pages',
'manage personalized content',
'administer blocks',
));
$this
->drupalLogin($admin_user);
// Create a new agent via the UI.
$agent_title = $this
->randomName();
$agent_name = personalize_generate_machine_name($agent_title, 'personalize_agent_machine_name_exists');
$edit = array(
'agent_basic_info[title]' => $agent_title,
'agent_basic_info[machine_name]' => $agent_name,
'agent_basic_info[agent_type]' => 'test_agent',
);
$this
->drupalPost('admin/structure/personalize/add', $edit, $this
->getButton('agent'));
$option_set = personalize_elements_get_option_set_for_variation('option-1', $agent_name, '#selector1', 'addCss', 'page1');
$var_num = acquia_lift_page_variation_create('first_variation_set', $option_set, array(
'personalize_elements_content' => 'test-class',
));
$this
->assertEqual(1, $var_num);
// Now create another option set and use it for the second variation.
$option_set_2 = personalize_elements_get_option_set_for_variation('option-2', $agent_name, '#selector2', 'editHtml', 'page1');
$var_num = acquia_lift_page_variation_create('first_variation_set', $option_set_2, array(
'personalize_elements_content' => '<p>some html</p>',
));
$this
->assertEqual(2, $var_num);
// Now use the first option set for variation 3.
$os_1 = personalize_option_set_load($option_set->osid, TRUE);
$var_num = acquia_lift_page_variation_create('first_variation_set', $os_1, array(
'personalize_elements_content' => 'another-test-class',
));
$this
->assertEqual(3, $var_num);
// Now add a different option to both for variation 4.
$os_1 = personalize_option_set_load($option_set->osid, TRUE);
$var_num = acquia_lift_page_variation_create('first_variation_set', $os_1, array(
'personalize_elements_content' => 'third-test-class',
));
$this
->assertEqual(4, $var_num);
// Rename the third variation to test if the new names persist across changes.
acquia_lift_page_variation_rename('first_variation_set', $agent_name, 3, 'three');
$os_2 = personalize_option_set_load($option_set_2->osid, TRUE);
$var_num = acquia_lift_page_variation_create('first_variation_set', $os_2, array(
'personalize_elements_content' => '<p>some other html</p>',
), 4);
$this
->assertEqual(4, $var_num);
// Try to create variation 6, it should correct it to 5.
$var_num = acquia_lift_page_variation_create('first_variation_set', $os_2, array(
'personalize_elements_content' => '<p>third html</p>',
), 6);
$this
->assertEqual(5, $var_num);
// Create another option set and add it to variation 1. (We need to
// make sure an option gets created for each subsequent variation.)
$option_set_3 = personalize_elements_get_option_set_for_variation('option-3', $agent_name, '#selector3', 'editText', 'page1');
$var_num = acquia_lift_page_variation_create('first_variation_set', $option_set_3, array(
'personalize_elements_content' => 'edited text',
), 1);
$this
->assertEqual(1, $var_num);
$this
->resetAll();
$option_sets = personalize_option_set_load_multiple(FALSE, array(
'agent' => $agent_name,
));
$osids = array_keys($option_sets);
$this
->assertEqual(3, count($option_sets));
foreach ($option_sets as $osid => $option_set) {
$this
->assertEqual('first_variation_set', $option_set->decision_name);
$this
->assertEqual(6, count($option_set->options));
}
$expected_options_os1 = array(
array(
'option_id' => PERSONALIZE_CONTROL_OPTION_ID,
'option_label' => PERSONALIZE_CONTROL_OPTION_LABEL,
),
array(
'option_id' => 'variation-1',
'option_label' => 'Variation #1',
'personalize_elements_content' => 'test-class',
),
array(
'option_id' => 'variation-2',
'option_label' => 'Variation #2',
),
array(
'option_id' => 'variation-3',
'option_label' => 'three',
'personalize_elements_content' => 'another-test-class',
),
array(
'option_id' => 'variation-4',
'option_label' => 'Variation #4',
'personalize_elements_content' => 'third-test-class',
),
array(
'option_id' => 'variation-5',
'option_label' => 'Variation #5',
),
);
$this
->assertEqual($expected_options_os1, $option_sets[$osids[0]]->options);
$expected_options_os2 = array(
array(
'option_id' => PERSONALIZE_CONTROL_OPTION_ID,
'option_label' => PERSONALIZE_CONTROL_OPTION_LABEL,
),
array(
'option_id' => 'variation-1',
'option_label' => 'Variation #1',
),
array(
'option_id' => 'variation-2',
'option_label' => 'Variation #2',
'personalize_elements_content' => '<p>some html</p>',
),
array(
'option_id' => 'variation-3',
'option_label' => 'three',
),
array(
'option_id' => 'variation-4',
'option_label' => 'Variation #4',
'personalize_elements_content' => '<p>some other html</p>',
),
array(
'option_id' => 'variation-5',
'option_label' => 'Variation #5',
'personalize_elements_content' => '<p>third html</p>',
),
);
$this
->assertEqual($expected_options_os2, $option_sets[$osids[1]]->options);
$expected_options_os3 = array(
array(
'option_id' => PERSONALIZE_CONTROL_OPTION_ID,
'option_label' => PERSONALIZE_CONTROL_OPTION_LABEL,
),
array(
'option_id' => 'variation-1',
'option_label' => 'Variation #1',
'personalize_elements_content' => 'edited text',
),
array(
'option_id' => 'variation-2',
'option_label' => 'Variation #2',
),
array(
'option_id' => 'variation-3',
'option_label' => 'three',
),
array(
'option_id' => 'variation-4',
'option_label' => 'Variation #4',
),
array(
'option_id' => 'variation-5',
'option_label' => 'Variation #5',
),
);
$this
->assertEqual($expected_options_os3, $option_sets[$osids[2]]->options);
// Rename the second variation.
acquia_lift_page_variation_rename('first_variation_set', $agent_name, 2, 'Hello');
$expected_options_os1[2]['option_label'] = 'Hello';
$expected_options_os2[2]['option_label'] = 'Hello';
$expected_options_os3[2]['option_label'] = 'Hello';
$option_sets = personalize_option_set_load_multiple(FALSE, array(
'decision_name' => 'first_variation_set',
'agent' => $agent_name,
));
$this
->assertEqual($expected_options_os1, $option_sets[$osids[0]]->options);
$this
->assertEqual($expected_options_os2, $option_sets[$osids[1]]->options);
$this
->assertEqual($expected_options_os3, $option_sets[$osids[2]]->options);
// Delete the third variation.
acquia_lift_page_variation_delete('first_variation_set', $agent_name, 3);
unset($expected_options_os1[3]);
unset($expected_options_os2[3]);
unset($expected_options_os3[3]);
$option_sets = personalize_option_set_load_multiple(FALSE, array(
'decision_name' => 'first_variation_set',
'agent' => $agent_name,
));
$this
->assertEqual($expected_options_os1, $option_sets[$osids[0]]->options);
$this
->assertEqual($expected_options_os2, $option_sets[$osids[1]]->options);
$this
->assertEqual($expected_options_os3, $option_sets[$osids[2]]->options);
// Delete another out of order and verify.
acquia_lift_page_variation_delete('first_variation_set', $agent_name, 1);
unset($expected_options_os1[1]);
unset($expected_options_os2[1]);
unset($expected_options_os3[1]);
$option_sets = personalize_option_set_load_multiple(FALSE, array(
'decision_name' => 'first_variation_set',
'agent' => $agent_name,
));
$this
->assertEqual($expected_options_os1, $option_sets[$osids[0]]->options);
$this
->assertEqual($expected_options_os2, $option_sets[$osids[1]]->options);
$this
->assertEqual($expected_options_os3, $option_sets[$osids[2]]->options);
// Now delete down to one left
acquia_lift_page_variation_delete('first_variation_set', $agent_name, 2);
acquia_lift_page_variation_delete('first_variation_set', $agent_name, 4);
unset($expected_options_os1[2]);
unset($expected_options_os2[2]);
unset($expected_options_os3[2]);
unset($expected_options_os1[4]);
unset($expected_options_os2[4]);
unset($expected_options_os3[4]);
$option_sets = personalize_option_set_load_multiple(FALSE, array(
'decision_name' => 'first_variation_set',
'agent' => $agent_name,
));
$this
->assertEqual($expected_options_os1, $option_sets[$osids[0]]->options);
$this
->assertEqual($expected_options_os2, $option_sets[$osids[1]]->options);
$this
->assertEqual($expected_options_os3, $option_sets[$osids[2]]->options);
// Delete the last and verify that all variations (including control) are
// removed.
acquia_lift_page_variation_delete('first_variation_set', $agent_name, 5);
$option_sets = personalize_option_set_load_multiple(FALSE, array(
'decision_name' => 'first_variation_set',
'agent' => $agent_name,
), TRUE);
$this
->assertTrue(count($option_sets) === 0);
}
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'),
);
}
public function testSaveAgent() {
// Create a new agent via the UI.
$agent = $this
->createTestAgent(array(
'control_rate' => 10,
'explore_rate' => 30,
));
$agent_name = $agent
->getTitle();
$machine_name = $agent
->getMachineName();
$expected_queue_items = $option_set_queue_items = array();
// Add some dummy option sets to this agent.
$option_set_values = array(
array(
'agent' => $machine_name,
'plugin' => 'type1',
'num_options' => 3,
),
array(
'agent' => $machine_name,
'plugin' => 'type2',
'num_options' => 2,
),
);
foreach ($option_set_values as $i => $values) {
list($option_set, $new_queues) = $this
->createOptionSet($i, $values);
$expected_queue_items = array_merge($expected_queue_items, $new_queues);
// We need to keep track of the option set items that get added to the
// queue separately from the other items as we need them again later.
// Dirty way to avoid 'saveAgent' method be included to $option_set_queue_items
$option_set_queue_items = array_merge($option_set_queue_items, $new_queues);
if ($i == 0) {
$expected_queue_items[] = array(
'method' => 'saveAgent',
'args' => array(
$machine_name,
$agent_name,
'adaptive',
PERSONALIZE_STATUS_NOT_STARTED,
0.1,
0.3,
1,
),
'agent' => $machine_name,
);
}
}
$this
->assertQueueItems($expected_queue_items);
$this->personalizedQueue
->deleteQueue();
$expected_queue_items = array();
// Save a goal for the agent.
$goal_name = 'form_submit';
personalize_goal_save($machine_name, $goal_name, 2);
$expected_queue_items[] = array(
'method' => 'saveGoal',
'args' => array(
$machine_name,
$goal_name,
),
'agent' => $machine_name,
);
$expected_queue_items[] = array(
'method' => 'saveAgent',
'args' => array(
$machine_name,
$agent_name,
'adaptive',
PERSONALIZE_STATUS_NOT_STARTED,
0.1,
0.3,
1,
),
'agent' => $machine_name,
);
$this
->assertQueueItems($expected_queue_items);
$this->personalizedQueue
->deleteQueue();
$expected_queue_items = array();
$this
->drupalPost("admin/structure/personalize/manage/{$machine_name}/edit", array(), $this
->getButton('agent'));
$expected_queue_items = array(
array(
'method' => 'saveAgent',
'args' => array(
$machine_name,
$agent_name,
'adaptive',
PERSONALIZE_STATUS_NOT_STARTED,
0.1,
0.3,
1,
),
'agent' => $machine_name,
),
);
$this
->assertQueueItems($expected_queue_items);
$this->personalizedQueue
->deleteQueue();
$expected_queue_items = array();
$this
->drupalPost("admin/structure/personalize/manage/{$machine_name}/edit", array(), $this
->getButton('agent'));
// Now the only thing that should get added is an item for the agent
// because neither goals nor option sets will have changed.
$expected_queue_items[] = array(
'method' => 'saveAgent',
'args' => array(
$machine_name,
$agent_name,
'adaptive',
PERSONALIZE_STATUS_NOT_STARTED,
0.1,
0.3,
1,
),
'agent' => $machine_name,
);
$this
->assertQueueItems($expected_queue_items);
$this->personalizedQueue
->deleteQueue();
// Create an MVT and add the two option sets to it.
$mvt_label = $this
->randomName();
$mvt_machine_name = personalize_generate_machine_name($mvt_label, 'personalize_mvt_machine_name_exists');
$edit = array(
'mvt[add][mvt_basic_info][label]' => $mvt_machine_name,
'mvt[add][mvt_basic_info][option_sets][]' => array(
1,
2,
),
);
$this
->drupalPost("admin/structure/personalize/manage/{$machine_name}/edit", $edit, $this
->getButton('mvt'));
// The option sets will get added to the queue
foreach ($option_set_queue_items as &$item) {
// The second argument, which is the decision point name, will have
// changed to the MVT name.
$item['args'][1] = $mvt_machine_name;
}
$expected_queue_items = array_slice($option_set_queue_items, 0, 5);
// @todo Commenting this out as for some reason after saving the new
// point and decision/choices for osid-1, it saves the old point and
// decision/choices for osid-2, before deleting the old osid-1 point,
// saving the second decision and deleting the osid-2 point.
//$this->assertQueueItems($expected_queue_items);
}
public function testSaveAutoTargetingRule() {
$agent = $this
->createTestAgent();
// as acquia_lift_context options are fetched from Acquia Lift via webservice - use hardcoded ones in tests
module_load_include('inc', 'personalize', 'personalize.admin');
$agentStructure = _personalize_agent_from_form_values(array(
'machine_name' => $agent
->getMachineName(),
'title' => $agent
->getTitle(),
'agent_type' => $agent
->getType(),
'data' => $agent
->getData(),
));
$agentStructure->data['visitor_context'] = array(
// Fake Aquia Lift context to check saveAutoTargetingRule method queue
'acquia_lift_context' => array(
'some_acquia_lift_context' => 'some_acquia_lift_context',
),
);
$this
->drupalGet('admin/structure/personalize/manage/' . $agent
->getMachineName() . '/edit');
personalize_agent_save($agentStructure);
$this
->drupalGet('admin/structure/personalize/manage/' . $agent
->getMachineName() . '/edit');
$agent = personalize_agent_load_agent($agent
->getMachineName(), TRUE);
$agentData = $agent
->getData();
$expected_queues = array(
array(
'method' => 'saveAgent',
'args' => array(
$agent
->getMachineName(),
$agent
->getTitle(),
$agentData['decision_style'],
PERSONALIZE_STATUS_NOT_STARTED,
0.1,
0.2,
1,
),
'agent' => $agent
->getMachineName(),
),
array(
'method' => 'saveAutoTargetingRule',
'args' => array(
$agent
->getMachineName(),
array_keys(array_filter($agentData['visitor_context']['acquia_lift_context'])),
),
'agent' => $agent
->getMachineName(),
),
);
$this
->assertQueueItems($expected_queues);
$this->personalizedQueue
->deleteQueue();
// Now remove the acquia_lift_context items and we should be sending a delete call
// to Acquia Lift.
$agentStructure->data['visitor_context'] = array(
'acquia_lift_context' => array(),
);
$this
->drupalGet('admin/structure/personalize/manage/' . $agent
->getMachineName() . '/edit');
personalize_agent_save($agentStructure);
$this
->drupalGet('admin/structure/personalize/manage/' . $agent
->getMachineName() . '/edit');
$agent = personalize_agent_load_agent($agent
->getMachineName(), TRUE);
$agentData = $agent
->getData();
$expected_queues = array(
array(
'method' => 'saveAgent',
'args' => array(
$agent
->getMachineName(),
$agent
->getTitle(),
$agentData['decision_style'],
PERSONALIZE_STATUS_NOT_STARTED,
0.1,
0.2,
1,
),
'agent' => $agent
->getMachineName(),
),
array(
'method' => 'deleteAutoTargetingRule',
'args' => array(
$agent
->getMachineName(),
),
'agent' => $agent
->getMachineName(),
),
);
$this
->assertQueueItems($expected_queues);
}
/**
* Tests syncing of Option Set information to Acquia Lift.
*/
public function testSyncOptionSets() {
$agent = $this
->createTestAgent();
// Create a couple of user profile fields for targeting.
$user_profile_field_1 = $this
->createUserProfileField();
$user_profile_field_2 = $this
->createUserProfileField();
// Include _personalize_agent_from_form_values() function to build agent data.
module_load_include('inc', 'personalize', 'personalize.admin');
$agentStructure = _personalize_agent_from_form_values(array(
'machine_name' => $agent
->getMachineName(),
'title' => $agent
->getTitle(),
'agent_type' => $agent
->getType(),
'data' => $agent
->getData(),
));
// Add the user profile fields as context.
$agentStructure->data['visitor_context'] = array(
'user_profile_context' => array(
str_replace('field_', '', $user_profile_field_1['field_name']) => str_replace('field_', '', $user_profile_field_1['field_name']),
str_replace('field_', '', $user_profile_field_2['field_name']) => str_replace('field_', '', $user_profile_field_2['field_name']),
),
);
personalize_agent_save($agentStructure);
$agent = personalize_agent_load_agent($agent
->getMachineName(), TRUE);
$agentData = $agent
->getData();
$agent_queue_item = array(
'method' => 'saveAgent',
'args' => array(
$agent
->getMachineName(),
$agent
->getTitle(),
$agentData['decision_style'],
PERSONALIZE_STATUS_NOT_STARTED,
$agentData['control_rate'] / 100,
$agentData['explore_rate'] / 100,
isset($agentData['cache_decisions']) && $agentData['cache_decisions'],
),
'agent' => $agent
->getMachineName(),
);
$expected_queues = array(
$agent_queue_item,
);
$this
->assertQueueItems($expected_queues);
$this->personalizedQueue
->deleteQueue();
$expected_queue_items = array();
// Now add an option set to the agent.
$personalized_blocks_form_state = array(
'values' => array(
'agent_select' => $agent
->getMachineName(),
'title' => $this
->randomName(),
'blocks' => array(
array(
'option_label' => 'Option A',
'option_id' => 'option-A',
'weight' => 0,
'block' => array(
'bid' => 'comment_delta_recent',
),
),
array(
'option_label' => 'Option B',
'option_id' => 'option-B',
'weight' => 1,
'block' => array(
'bid' => 'system_delta_main',
),
),
array(
'option_label' => 'Option C',
'option_id' => 'option-C',
'weight' => 2,
'block' => array(
'bid' => 'system_delta_help',
),
),
),
),
);
personalize_option_set_save(_personalize_blocks_convert_form_to_personalized_block($personalized_blocks_form_state));
$option_sets = personalize_option_set_load_by_agent($agent
->getMachineName(), TRUE);
$osid = key($option_sets);
$option_set = $option_sets[$osid];
$point_name = personalize_get_decision_point_name_for_option_set($option_set);
$decision_name = personalize_get_decision_name_for_option_set($option_set);
$agent = personalize_agent_load_agent($agent
->getMachineName(), TRUE);
$agentData = $agent
->getData();
$this
->assertTrue(isset($agentData['decisions']) && isset($agentData['decisions'][$osid]));
$expected_queue_items['point'] = array(
'method' => 'savePoint',
'args' => array(
$agent
->getMachineName(),
$point_name,
),
'agent' => $agent
->getMachineName(),
);
$expected_queue_items['decision'] = array(
'method' => 'saveDecision',
'args' => array(
$agent
->getMachineName(),
$point_name,
$decision_name,
),
'agent' => $agent
->getMachineName(),
);
foreach ($option_set->options as $key => $option) {
$expected_queue_items[$option['option_id']] = array(
'method' => 'saveChoice',
'args' => array(
$agent
->getMachineName(),
$point_name,
$decision_name,
personalize_generate_option_id($key),
),
'agent' => $agent
->getMachineName(),
);
}
$expected_queue_items['agent'] = $agent_queue_item;
$this
->assertQueueItems(array_values($expected_queue_items));
$this->personalizedQueue
->deleteQueue();
// Set up fixed targeting on Option A with two features OR'd together.
$context_1 = str_replace('field_', '', $user_profile_field_1['field_name']);
$context_2 = str_replace('field_', '', $user_profile_field_2['field_name']);
// We can't use the form to add multiple fixed targeting contexts because we can't
// make simpletest use the "Add context" button, so we send our form values directly
// to the submit function.
module_load_include('inc', 'personalize', 'personalize.admin');
$form_state = array(
'values' => array(
'agent' => $agent
->getMachineName(),
'option_sets' => array(
'option_set_1' => array(
'winner' => 'option-A',
'advanced' => array(
'label' => $personalized_blocks_form_state['values']['title'],
'stateful' => 0,
),
'options' => array(
'option-A' => array(
'explicit_targeting' => array(
'mapping' => array(
'contexts' => array(
array(
'context' => 'user_profile_context' . PERSONALIZE_TARGETING_ADMIN_SEPARATOR . $context_1,
'value' => array(
'match' => 'some value',
'operator' => 'equals',
),
),
array(
'context' => 'user_profile_context' . PERSONALIZE_TARGETING_ADMIN_SEPARATOR . $context_2,
'value' => array(
'match' => 'some other value',
'operator' => 'contains',
),
),
),
),
'strategy' => 'OR',
),
),
),
),
),
),
);
personalize_agent_option_sets_form_submit(array(), $form_state);
$feature_1 = $context_1 . '::some-value';
$feature_2 = $context_2 . '::sc-some-other-value';
$expected_queue_items['targeting'] = array(
'method' => 'saveFixedTargetingMapping',
'args' => array(
$agent
->getMachineName(),
$point_name,
array(
array(
'feature' => $feature_1,
'decision' => $decision_name . ':option-A',
),
array(
'feature' => $feature_2,
'decision' => $decision_name . ':option-A',
),
),
),
'agent' => $agent
->getMachineName(),
);
// Because the decision structure has not changed only the agent and targeting
// should be sync'd.
$this
->assertQueueItems(array(
$expected_queue_items['agent'],
$expected_queue_items['targeting'],
));
$this->personalizedQueue
->deleteQueue();
// Change the fixed targeting strategy to AND the features together.
$edit = array(
'option_sets[option_set_1][options][option-A][explicit_targeting][strategy]' => 'AND',
);
$this
->drupalPost('admin/structure/personalize/manage/' . $agent
->getMachineName() . '/edit', $edit, $this
->getButton('option'));
// Now the fixed targeting mapping should have a single mapping with
// comma-separated features.
$expected_queue_items['targeting']['args'][2] = array(
array(
'feature' => $feature_1 . ',' . $feature_2,
'decision' => $decision_name . ':option-A',
),
);
$this
->assertQueueItems(array(
$expected_queue_items['agent'],
$expected_queue_items['targeting'],
));
$this->personalizedQueue
->deleteQueue();
// Remove Option B
$this
->drupalGet('admin/structure/personalize/variations/personalize-blocks/manage/' . $osid . '/edit');
$this
->drupalPost(NULL, array(), 'remove_1');
$this
->drupalPost(NULL, array(), t('Save'));
$expected_queue_items['delete-B'] = array(
'method' => 'deleteChoice',
'args' => array(
$agent
->getMachineName(),
$point_name,
$decision_name,
'option-B',
),
'agent' => $agent
->getMachineName(),
);
$new_queue_items = array();
$expected_order = array(
'point',
'decision',
'option-A',
'option-C',
'delete-B',
'agent',
'targeting',
);
foreach ($expected_order as $key) {
$new_queue_items[$key] = $expected_queue_items[$key];
}
$this
->assertQueueItems(array_values($new_queue_items));
$this->personalizedQueue
->deleteQueue();
}
public function testSyncGoalsFromCampaignUI() {
$agent = $this
->createTestAgent();
$edit = array(
'goals[0][action_name]' => 'form_submit',
'goals[0][value]' => '20',
);
$this
->drupalPost('admin/structure/personalize/manage/' . $agent
->getMachineName() . '/edit', $edit, $this
->getButton('goal'));
$expected_queues = array(
array(
'method' => 'saveGoal',
'args' => array(
$agent
->getMachineName(),
'form_submit',
),
'agent' => $agent
->getMachineName(),
),
array(
'method' => 'saveAgent',
'args' => array(
$agent
->getMachineName(),
$agent
->getTitle(),
'adaptive',
PERSONALIZE_STATUS_NOT_STARTED,
0.1,
0.2,
1,
),
'agent' => $agent
->getMachineName(),
),
);
$this
->assertQueueItems($expected_queues);
$this->personalizedQueue
->deleteQueue();
$this
->drupalPost('admin/structure/personalize/manage/' . $agent
->getMachineName() . '/edit', array(), $this
->getButton('goal'));
// As we're triggering only goals form and do not change anything
// saveAgent won't be invoked also
$expected_queues = array();
$this
->assertQueueItems($expected_queues);
$this->personalizedQueue
->deleteQueue();
}
public function testSyncGoalsFromVisitorUI() {
// include visitor_actions_action_name_exists() function to validate action machine name
module_load_include('inc', 'visitor_actions', 'visitor_actions.admin');
$agent = $this
->createTestAgent();
$actionTitle = $this
->randomName();
$actionMachineName = personalize_generate_machine_name($actionTitle, 'visitor_actions_action_name_exists');
// Create new Visitor Action but WITHOUT connection to active agent
$edit = array(
'title' => $actionTitle,
'machine_name' => $actionMachineName,
'actionable_element' => 'form',
'identifier[form]' => 'some_form_id',
'event[form]' => 'server::submit_server',
'personalize_goal' => FALSE,
'personalize_goal_value' => 50,
);
$this
->drupalPost('admin/structure/visitor_actions/add', $edit, $this
->getButton());
// Without connection to the agent we should run any acquia_lift' syncing
// @see personalize_visitor_action_form_submit()
$expected_queues = array();
$this
->assertQueueItems($expected_queues);
// Try to create new with connection to the agent
$actionTitle = $this
->randomName();
$actionMachineName = personalize_generate_machine_name($actionTitle, 'visitor_actions_action_name_exists');
// Create new Visitor Action but WITH connection to active agent
$edit = array(
'title' => $actionTitle,
'machine_name' => $actionMachineName,
'actionable_element' => 'form',
'identifier[form]' => 'some_form_id',
'event[form]' => 'server::submit_server',
'personalize_goal' => TRUE,
'personalize_goal_value' => 50,
);
$this
->drupalPost('admin/structure/visitor_actions/add', $edit, $this
->getButton());
// With connection to the agent we should run AcquiaLiftAgent->syncGoals
$expected_queues = array(
array(
'method' => 'saveGoal',
'args' => array(
$agent
->getMachineName(),
$actionMachineName,
),
'agent' => $agent
->getMachineName(),
),
array(
'method' => 'saveAgent',
'args' => array(
$agent
->getMachineName(),
$agent
->getTitle(),
'adaptive',
PERSONALIZE_STATUS_NOT_STARTED,
0.1,
0.2,
1,
),
'agent' => $agent
->getMachineName(),
),
);
$this
->assertQueueItems($expected_queues);
$this->personalizedQueue
->deleteQueue();
// Remove machine name from post because it's not available as a field in the edit form.
unset($edit['machine_name']);
// Try to modify with same goal value to check that anything won't be synced
$this
->drupalPost('admin/structure/visitor_actions/manage/' . $actionMachineName . '/edit', $edit, $this
->getButton());
// With connection to the agent but with old goal value we should not run AcquiaLiftAgent->syncGoals or saveAgent
$expected_queues = array();
$this
->assertQueueItems($expected_queues);
$this->personalizedQueue
->deleteQueue();
// If goal value is changed syncGoals and saveAgent should be invoked
$edit['personalize_goal_value'] += 10;
$this
->drupalPost('admin/structure/visitor_actions/manage/' . $actionMachineName . '/edit', $edit, $this
->getButton());
// With connection to the agent but with old goal value we should not run AcquiaLiftAgent->syncGoals or saveAgent
$expected_queues = array(
array(
'method' => 'saveGoal',
'args' => array(
$agent
->getMachineName(),
$actionMachineName,
),
'agent' => $agent
->getMachineName(),
),
array(
'method' => 'saveAgent',
'args' => array(
$agent
->getMachineName(),
$agent
->getTitle(),
'adaptive',
PERSONALIZE_STATUS_NOT_STARTED,
0.1,
0.2,
1,
),
'agent' => $agent
->getMachineName(),
),
);
$this
->assertQueueItems($expected_queues);
$this->personalizedQueue
->deleteQueue();
$this
->resetAll();
// Verify that agent has last visitor action data
$agentGoals = personalize_goal_load_by_conditions(array(
'agent' => $agent
->getMachineName(),
));
$firstGoal = reset($agentGoals);
$this
->assertEqual($firstGoal->action, $actionMachineName);
$this
->assertEqual($firstGoal->value, $edit['personalize_goal_value']);
// Try to delete goal that connected to Agent from Visitor Action UI
$this
->drupalPost('admin/structure/visitor_actions/manage/' . $actionMachineName . '/delete', array(), t('Delete'));
$expected_queues = array(
array(
'method' => 'deleteGoal',
'args' => array(
$agent
->getMachineName(),
$actionMachineName,
),
'agent' => $agent
->getMachineName(),
),
array(
'method' => 'saveAgent',
'args' => array(
$agent
->getMachineName(),
$agent
->getTitle(),
'adaptive',
PERSONALIZE_STATUS_NOT_STARTED,
0.1,
0.2,
1,
),
'agent' => $agent
->getMachineName(),
),
);
$this
->assertQueueItems($expected_queues);
$this->personalizedQueue
->deleteQueue();
$this
->resetAll();
// No goal should be attached after deletion
$agentGoals = personalize_goal_load_by_conditions(array(
'agent' => $agent
->getMachineName(),
));
$this
->assertEqual($agentGoals, array());
}
public function testDeleteAgentGoals() {
$agent = $this
->createTestAgent();
$agent_name = $agent
->getMachineName();
// Add goals.
personalize_goal_save($agent_name, 'first-goal', 1);
personalize_goal_save($agent_name, 'second-goal', 1);
$this
->resetAll();
// Clear the queue as we're just testing goal deletion.
$this->personalizedQueue
->deleteQueue();
$goals = personalize_goal_load_by_conditions(array(
'agent' => $agent_name,
));
$this
->assertEqual(2, count($goals));
$goal_ids = array_keys($goals);
$first_goal_id = $goal_ids[0];
$second_goal_id = $goal_ids[1];
// Delete one of the goals.
personalize_goal_delete($first_goal_id);
$expected_queues = array(
array(
'method' => 'saveGoal',
'args' => array(
$agent_name,
$goals[$second_goal_id]->action,
),
'agent' => $agent_name,
),
array(
'method' => 'deleteGoal',
'args' => array(
$agent_name,
$goals[$first_goal_id]->action,
),
'agent' => $agent_name,
),
array(
'method' => 'saveAgent',
'args' => array(
$agent_name,
$agent
->getTitle(),
'adaptive',
PERSONALIZE_STATUS_NOT_STARTED,
0.1,
0.2,
1,
),
'agent' => $agent_name,
),
);
$this
->assertQueueItems($expected_queues);
}
public function testUpdateAgentStatus() {
$agent = $this
->createTestAgent();
$agent_name = $agent
->getMachineName();
// 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();
// Now use the API function to update the status.
personalize_agent_set_status($agent_name, PERSONALIZE_STATUS_PAUSED);
$expected_queues = array(
array(
'method' => 'updateAgentStatus',
'args' => array(
$agent_name,
PERSONALIZE_STATUS_PAUSED,
),
'agent' => $agent_name,
),
);
$this
->assertQueueItems($expected_queues);
$this->personalizedQueue
->deleteQueue();
}
/**
* Tests that agents are paused when they need to be paused.
*/
function testPauseAgents() {
// Create an agent with a couple of option sets and a couple of goals.
$control_rate = 10;
$explore_rate = 30;
$agent_name = 'my-test-lift-agent';
$this
->createTestAgent(array(
'name' => $agent_name,
'control_rate' => $control_rate,
'explore_rate' => $explore_rate,
));
$option_set_values = array(
array(
'agent' => $agent_name,
'plugin' => 'type1',
'option_ids' => array(
'option-1',
'option-2',
),
),
array(
'agent' => $agent_name,
'plugin' => 'type2',
'option_ids' => array(
'option-a',
'option-b',
'option-c',
),
),
);
$option_sets = array();
foreach ($option_set_values as $i => $values) {
list($option_set, $new_queue_items) = $this
->createOptionSet($i, $values);
$option_sets[] = $option_set;
}
$first_osid = $option_sets[0]->osid;
$second_osid = $option_sets[1]->osid;
// Add goals.
personalize_goal_save($agent_name, 'first-goal', 1);
personalize_goal_save($agent_name, 'second-goal', 1);
$this
->resetAll();
$goals = array();
foreach (personalize_goal_load_by_conditions(array(
'agent' => $agent_name,
)) as $goal) {
$goals[] = $goal;
}
// 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_name), PERSONALIZE_STATUS_RUNNING);
// Delete a goal - this should not pause the agent.
personalize_goal_delete($goals[0]->id);
$this
->resetAll();
$status = personalize_agent_get_status($agent_name);
$this
->assertEqual($status, PERSONALIZE_STATUS_RUNNING);
// Now delete the remaining goal - this should pause the agent.
personalize_goal_delete($goals[1]->id);
$this
->resetAll();
$status = personalize_agent_get_status($agent_name);
$this
->assertEqual($status, PERSONALIZE_STATUS_PAUSED);
// Add a goal back and set it to running again.
personalize_goal_save($agent_name, 'third-goal', 1);
variable_set(_personalize_agent_get_status_variable($agent_name), PERSONALIZE_STATUS_RUNNING);
// Delete an option set - this should not pause the agent.
personalize_option_set_delete($first_osid);
$this
->resetAll();
$status = personalize_agent_get_status($agent_name);
$this
->assertEqual($status, PERSONALIZE_STATUS_RUNNING);
// Delete an option from the remaining option set, it should remain running
$option_set = personalize_option_set_load($second_osid);
unset($option_set->options[2]);
$option_set = personalize_option_set_save($option_set);
$this
->resetAll();
$status = personalize_agent_get_status($agent_name);
$this
->assertEqual($status, PERSONALIZE_STATUS_RUNNING);
// Delete another option, it should be paused.
unset($option_set->options[1]);
$option_set = personalize_option_set_save($option_set);
$this
->resetAll();
$status = personalize_agent_get_status($agent_name);
$this
->assertEqual($status, PERSONALIZE_STATUS_PAUSED);
// Clear the queue.
$this->personalizedQueue
->deleteQueue();
// Add the option back and start the campaign again.
$option_set->options[1] = array(
'option_id' => 'new-option',
'option_label' => 'New Option',
);
$option_set = personalize_option_set_save($option_set);
$this
->resetAll();
variable_set(_personalize_agent_get_status_variable($agent_name), PERSONALIZE_STATUS_RUNNING);
// Cause the queue to fail based on a bad request.
AcquiaLiftAPI::setTestInstance(TRUE, TRUE);
// Run the queue - the 400 error will abort the queue and the handleFailedItem() method
// should pause the agent.
$_SESSION['acquia_lift_queue_trigger'] = true;
acquia_lift_process_queue(FALSE);
$this
->resetAll();
$status = personalize_agent_get_status($agent_name);
$this
->assertEqual($status, PERSONALIZE_STATUS_PAUSED);
// Set it to running again and delete that last remaining option set.
variable_set(_personalize_agent_get_status_variable($agent_name), PERSONALIZE_STATUS_RUNNING);
personalize_option_set_delete($second_osid);
$this
->resetAll();
$status = personalize_agent_get_status($agent_name);
$this
->assertEqual($status, PERSONALIZE_STATUS_PAUSED);
}
}
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'),
);
}
public function testAcquiaLiftQueue() {
$marketer = $this
->drupalCreateUser(array(
'access administration pages',
'manage personalized content',
));
$this
->drupalLogin($marketer);
// Create a new agent via the UI.
$agent = $this
->createTestAgent(array(), FALSE);
$agent_name = $agent
->getTitle();
$machine_name = $agent
->getMachineName();
// There should now be a js setting for triggering queue processing.
$settings = $this
->drupalGetSettings();
$this
->assertEqual(1, $settings['acquia_lift']['sync_queue']);
$expected_queue_items = array();
$queued_agent_item = array(
'method' => 'saveAgent',
'args' => array(
$machine_name,
$agent_name,
'adaptive',
PERSONALIZE_STATUS_NOT_STARTED,
0.1,
0.2,
1,
),
'agent' => $machine_name,
);
$expected_queue_items[] = $queued_agent_item;
$this
->assertQueueItems($expected_queue_items);
// Now cause the queue to be processed, which would normally happen
// via an ajax request.
$this
->drupalGet('acquia_lift/queue');
// Confirm that the queue is now empty.
$this
->assertQueueItems(array());
$this
->drupalGet('admin/structure/personalize');
$this
->assertNoText(t('At least one of your campaigns has configuration that has not been fully synchronized with Acquia Lift. This should resolve itself on the next cron run.'));
// Now save it again but don't process the queue.
$this
->drupalPost("admin/structure/personalize/manage/{$machine_name}/edit", array(), $this
->getButton('agent'));
// Save a goal for the agent.
$goal_name = 'form_submit';
personalize_goal_save($machine_name, $goal_name, 2);
$expected_queue_items = array();
$expected_queue_items[] = $queued_agent_item;
$expected_queue_items[] = array(
'method' => 'saveGoal',
'args' => array(
$machine_name,
$goal_name,
),
'agent' => $machine_name,
);
$expected_queue_items[] = $queued_agent_item;
$this
->assertQueueItems($expected_queue_items);
// Since we can't simulate the queued requests timing out during a web
// test, we simply unset the queue trigger session without processing
// the queue.
$this
->assertTrue(isset($_SESSION['acquia_lift_queue_trigger']));
// Log the user out and back in again to get rid of the session variable.
$this
->drupalLogout();
$this
->drupalLogin($marketer);
// Now they should get a message warning them that there are items that
// need to get sync'd to Acquia Lift.
$this
->drupalGet('admin/structure/personalize');
$this
->assertText(t('At least one of your campaigns has configuration that has not been fully synchronized with Acquia Lift. This should resolve itself on the next cron run.'));
$this
->drupalLogout();
$admin_user = $this
->drupalCreateUser(array(
'administer site configuration',
'access administration pages',
'manage personalized content',
));
$this
->drupalLogin($admin_user);
$this
->drupalGet('admin/structure/personalize');
$this
->assertRaw(t('At least one of your campaigns has configuration that has not been fully synchronized with Acquia Lift. This should resolve itself on the next cron run.') . t(' Click here to <a href="@cron">run cron manually</a>.', array(
'@cron' => url('admin/reports/status/run-cron'),
)));
// Now run cron
$this
->drupalGet('admin/reports/status/run-cron');
$this
->assertQueueItems(array());
// Now save the agent again.
$this
->drupalPost("admin/structure/personalize/manage/{$machine_name}/edit", array(), $this
->getButton('agent'));
$expected_queue_items = array(
$queued_agent_item,
);
$this
->assertQueueItems($expected_queue_items);
// Cause the queue to fail.
AcquiaLiftAPI::setTestInstance(TRUE);
// Run the queue.
$_SESSION['acquia_lift_queue_trigger'] = true;
acquia_lift_process_queue(FALSE);
$expected_logs = array();
for ($i = 0; $i <= AcquiaLiftQueue::MAX_RETRIES; $i++) {
$expected_logs[] = array(
'level' => 'error',
'message' => "The campaign {$machine_name} could not be pushed to Acquia Lift",
);
}
$test_logger = new AcquiaLiftTestLogger(FALSE);
$logs = $test_logger
->getLogs();
$this
->assertEqual($expected_logs, $logs);
// Item should be removed after final attempt.
$this
->assertQueueItems(array());
$test_logger
->clearLogs();
// Edit the agent again.
$edit = array(
'cache_decisions' => FALSE,
);
$this
->drupalPost("admin/structure/personalize/manage/{$machine_name}/edit", $edit, $this
->getButton('agent'));
personalize_agent_set_status($machine_name, PERSONALIZE_STATUS_PAUSED);
$this
->resetAll();
$queued_agent_item['args'][6] = FALSE;
$expected_queue_items = array(
$queued_agent_item,
);
$expected_queue_items[] = array(
'method' => 'updateAgentStatus',
'args' => array(
$machine_name,
PERSONALIZE_STATUS_PAUSED,
),
'agent' => $machine_name,
);
$this
->assertQueueItems($expected_queue_items);
$this
->resetAll();
// Cause the queue to fail based on a bad request. There should not be any retries,
// it should just be aborted.
AcquiaLiftAPI::setTestInstance(TRUE, TRUE);
// 2nd param specifies simulating client-side error, i.e. 400 error.
// Run the queue.
$_SESSION['acquia_lift_queue_trigger'] = true;
acquia_lift_process_queue(FALSE);
$expected_logs = array();
$expected_logs[] = array(
'level' => 'error',
'message' => "The campaign {$machine_name} could not be pushed to Acquia Lift",
);
$logs = $test_logger
->getLogs();
$this
->assertEqual($expected_logs, $logs);
// Item should be removed after final attempt.
$this
->assertQueueItems(array());
}
/**
* Tests the logic in AcquiaLiftAgent's implementation of convertContextToFeatureString().
*/
public function testConvertContextToFeatureString() {
// No truncation should happen if name and value are short enough.
$name = $this
->randomName(20);
$value = $this
->randomName(20);
$string = AcquiaLiftAgent::convertContextToFeatureString($name, $value);
$expected = $name . '::' . $value;
$this
->assertEqual($expected, $string);
$string = AcquiaLiftAgent::convertContextToFeatureString($name, $value, TRUE);
$expected = $name . ':' . $value;
$this
->assertEqual($expected, $string);
// If we have a really long name and value test that they are truncated
// correctly.
$long_name = $this
->randomName(40);
$long_value = $this
->randomName(40);
$string = AcquiaLiftAgent::convertContextToFeatureString($long_name, $long_value);
$expected = substr($long_name, 0, 24) . '::' . substr($long_value, 0, 24);
$this
->assertEqual($expected, $string);
$string = AcquiaLiftAgent::convertContextToFeatureString($long_name, $long_value, TRUE);
$expected = substr($long_name, 0, 24) . ':' . substr($long_value, 0, 25);
$this
->assertEqual($expected, $string);
}
/**
* Tests that new agents on the site cannot override existing agents in Lift.
*/
public function testMachineNameValidation() {
$test_data = array(
'agents' => array(
array(
'code' => 'my-existing-agent',
),
),
);
variable_set('acquia_lift_web_test_data', $test_data);
// Try to create a new agent with the same name as one that exists in Lift.
$this
->createTestAgent(array(
'name' => 'my-existing-agent',
'control_rate' => 10,
'explore_rate' => 30,
), TRUE, FALSE);
$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 AcquiaLiftAgentInterface);
}
/**
* Tests the function that gathers operations for syncing of agents and their
* components to Lift.
*/
public function testBatchSyncOperations() {
// Create an agent on the site with a couple of option sets.
// Note: we do this part first rather than loading the test data to
// the server because otherwise it wouldn't allow us to create an
// agent with the same name as an existing one.
$control_rate = 10;
$explore_rate = 30;
$this
->createTestAgent(array(
'name' => 'first-existing-agent',
'control_rate' => $control_rate,
'explore_rate' => $explore_rate,
));
$option_set_values = array(
array(
'agent' => 'first-existing-agent',
'plugin' => 'type1',
'option_ids' => array(
'option-1',
'option-2',
),
),
array(
'agent' => 'first-existing-agent',
'plugin' => 'type2',
'option_ids' => array(
'option-a',
'option-b',
'option-c',
),
),
);
$option_sets = array();
foreach ($option_set_values as $i => $values) {
list($option_set, $new_queue_items) = $this
->createOptionSet($i, $values);
$option_sets[] = $option_set;
}
$first_osid = 'osid-' . $option_sets[0]->osid;
$second_osid = 'osid-' . $option_sets[1]->osid;
// Add a goal.
personalize_goal_save('first-existing-agent', 'new-goal', 2);
$this
->resetAll();
// Set up some test data to be returned by the dummy http client.
$test_data = array(
'agents' => array(
array(
'code' => 'first-existing-agent',
),
),
'points' => array(
'first-existing-agent' => array(
// The agent on the Drupal site will have this point.
$first_osid,
// The agent on the Drupal site will not have this point so it
// should get deleted upon sync.
'second-point',
),
),
'decisions' => array(
'first-existing-agent' => array(
$first_osid => array(
$first_osid,
// This decision should get deleted upon sync.
'another-decision',
),
),
),
'choices' => array(
'first-existing-agent' => array(
$first_osid => array(
$first_osid => array(
'option-1',
'option-2',
// These choices should get deleted upon sync.
'option-3',
'last-option',
),
),
),
),
'goals' => array(
'first-existing-agent' => array(
// This goal should get deleted upon sync.
'first-goal',
),
),
);
variable_set('acquia_lift_web_test_data', $test_data);
// Now try syncing this agent to Lift.
$agents = personalize_agent_load_multiple(array(
'first-existing-agent',
));
// Ensure the test API client is used during the call for operations.
AcquiaLiftAPI::setTestInstance();
module_load_include('inc', 'acquia_lift', 'acquia_lift.batch');
// Confirm that the correct operations will be performed.
$operations = acquia_lift_get_sync_operations_for_agents($agents);
$expected_operations = array(
array(
'method' => 'saveAgent',
'args' => array(
'first-existing-agent',
'first-existing-agent',
'adaptive',
PERSONALIZE_STATUS_NOT_STARTED,
$control_rate / 100,
$explore_rate / 100,
TRUE,
),
),
// PUT requests for all the points, decisions and choices that exist
// in the agent being sync'd, regardless of whether they already exist
// in Lift.
array(
'method' => 'savePoint',
'args' => array(
'first-existing-agent',
$first_osid,
),
),
array(
'method' => 'saveDecision',
'args' => array(
'first-existing-agent',
$first_osid,
$first_osid,
),
),
array(
'method' => 'saveChoice',
'args' => array(
'first-existing-agent',
$first_osid,
$first_osid,
'option-1',
),
),
array(
'method' => 'saveChoice',
'args' => array(
'first-existing-agent',
$first_osid,
$first_osid,
'option-2',
),
),
array(
'method' => 'savePoint',
'args' => array(
'first-existing-agent',
$second_osid,
),
),
array(
'method' => 'saveDecision',
'args' => array(
'first-existing-agent',
$second_osid,
$second_osid,
),
),
array(
'method' => 'saveChoice',
'args' => array(
'first-existing-agent',
$second_osid,
$second_osid,
'option-a',
),
),
array(
'method' => 'saveChoice',
'args' => array(
'first-existing-agent',
$second_osid,
$second_osid,
'option-b',
),
),
array(
'method' => 'saveChoice',
'args' => array(
'first-existing-agent',
$second_osid,
$second_osid,
'option-c',
),
),
// DELETE request for non-existent choices.
array(
'method' => 'deleteChoice',
'args' => array(
'first-existing-agent',
$first_osid,
$first_osid,
'option-3',
),
),
array(
'method' => 'deleteChoice',
'args' => array(
'first-existing-agent',
$first_osid,
$first_osid,
'last-option',
),
),
// DELETE request for non-existent decision.
array(
'method' => 'deleteDecision',
'args' => array(
'first-existing-agent',
$first_osid,
'another-decision',
),
),
// DELETE request for non-existent decision point.
array(
'method' => 'deletePoint',
'args' => array(
'first-existing-agent',
'second-point',
),
),
// PUT request for the new goal
array(
'method' => 'saveGoal',
'args' => array(
'first-existing-agent',
'new-goal',
),
),
// DELETE request for the goal that exists in Lift but not in the agent
// being sync'd.
array(
'method' => 'deleteGoal',
'args' => array(
'first-existing-agent',
'first-goal',
),
),
);
$this
->assertEqual($expected_operations, $operations);
}
}
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 testConversionReportAjaxEndpoint() {
$this
->drupalLogin($this->managerUser);
$agent = $this
->createTestAgent(array(), TRUE, FALSE);
$agent_name = $agent
->getMachineName();
// Set the agent to read report data from the test file.
$path = drupal_get_path('module', 'acquia_lift');
variable_set("acquia_lift_report_source_" . $agent_name, "/" . $path . '/tests/test_reports.json');
// Call the conversion report endpoint.
$first_osid = 'osid-1';
$report = $this
->drupalGet('acquia_lift/reports/conversion', array(
'query' => array(
'campaign' => $agent_name,
'decision' => $first_osid,
),
));
$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_name, 'Campaign 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.');
}
public function testReadReportsFromFile() {
$this
->drupalLogin($this->managerUser);
$first_agent = 'new-test-agent';
$second_agent = 'second-test-agent';
$control_rate = 10;
$explore_rate = 30;
$this
->createTestAgent(array(
'name' => $first_agent,
'control_rate' => $control_rate,
'explore_rate' => $explore_rate,
));
// Our second agent will continu to read reports from the API when our first switches
// to reading from a file.
$this
->createTestAgent(array(
'name' => $second_agent,
'control_rate' => $control_rate,
'explore_rate' => $explore_rate,
));
$test_data = array();
// Set each agent up with an option set with 2 options, and a goal, and set it to
// running.
$option_sets = array();
foreach (array(
$first_agent,
$second_agent,
) as $i => $agent_name) {
list($option_set, $new_queue_items) = $this
->createOptionSet($i, array(
'agent' => $agent_name,
'plugin' => 'type1',
'option_ids' => array(
'option-1',
'option-2',
),
));
$option_sets[] = $option_set;
$osid = $option_set->osid;
// Add a goal.
personalize_goal_save($agent_name, 'new-goal', 1);
// 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_name), PERSONALIZE_STATUS_RUNNING);
// Set the started time of the agent to now.
$agent = personalize_agent_load($agent_name);
$started = time();
$agent->started = $started;
personalize_agent_save($agent);
$report_start_date = 1407499650;
// Test to ensure that an initial report at this point returns no data.
AcquiaLiftAPI::setTestInstance();
$agent_instance = personalize_agent_load_agent($first_agent);
$report = $agent_instance
->buildCampaignReports(array(
'decision' => 'osid-' . $option_sets[0]->osid,
'start' => $report_start_date,
));
$this
->assertFalse($report['#has_data'], 'Report has no data.');
// Add some test data so that calls to get reports for this agent will
// return basic reports.
$test_data = array_merge_recursive($test_data, array(
// We need to replicate this test agent on the server so that the errors()
// check will pass.
'agents' => array(
array(
'code' => $agent_name,
),
),
'points' => array(
$agent_name => array(
$osid,
),
),
'decisions' => array(
$agent_name => array(
$osid => array(
$osid,
),
),
),
'choices' => array(
$agent_name => array(
$osid => array(
$osid => array(
'option-1',
'option-2',
),
),
),
),
'goals' => array(
$agent_name => array(
// This goal should get deleted upon sync.
'new-goal',
),
),
// Now add the reports.
'reports' => array(
$agent_name => array(
'confidence' => AcquiaLiftTestReports::getBasicConfidenceReport($agent_name),
'targeting-features' => AcquiaLiftTestReports::getBasicTargetingReport($agent_name),
'learning' => array(),
'agent-status' => AcquiaLiftTestReports::getBasicStatusReport($agent_name),
'context-filters' => AcquiaLiftTestReports::getBasicContextFilters(),
),
),
));
}
variable_set('acquia_lift_web_test_data', $test_data);
$this
->resetAll();
AcquiaLiftAPI::setTestInstance();
$agent_instance = personalize_agent_load_agent($first_agent);
// We use the date that the test report was created.
$report = $agent_instance
->buildCampaignReports(array(
'decision' => 'osid-' . $option_sets[0]->osid,
'start' => $report_start_date,
));
$this
->assertFalse($report['#has_data'], 'Empty reports have no data to show.');
// The experiment report should show that Option A has a 0% conversion rate.
$this
->assertEqual("Option A", $report['experiment']['reports']['conversion']['reports']['summary']['summary_holder']['summary_table']['#rows'][0]['data'][0]['data']);
$this
->assertEqual("Control", $report['experiment']['reports']['conversion']['reports']['summary']['summary_holder']['summary_table']['#rows'][0]['data'][0]['data-acquia-lift-variation-label']);
$this
->assertEqual("0%", $report['experiment']['reports']['conversion']['reports']['summary']['summary_holder']['summary_table']['#rows'][0]['data'][2]['data']);
// The report for the second agent will be identical
$agent_instance = personalize_agent_load_agent($second_agent);
$report = $agent_instance
->buildCampaignReports(array(
'decision' => 'osid-' . $option_sets[0]->osid,
'start' => $report_start_date,
));
$this
->assertEqual("Option A", $report['experiment']['reports']['conversion']['reports']['summary']['summary_holder']['summary_table']['#rows'][0]['data'][0]['data']);
$this
->assertEqual("Control", $report['experiment']['reports']['conversion']['reports']['summary']['summary_holder']['summary_table']['#rows'][0]['data'][0]['data-acquia-lift-variation-label']);
$this
->assertEqual("0%", $report['experiment']['reports']['conversion']['reports']['summary']['summary_holder']['summary_table']['#rows'][0]['data'][2]['data']);
$agent_instance = NULL;
$this
->resetAll();
// Now set the first agent to use a report from a file.
$path = drupal_get_path('module', 'acquia_lift');
variable_set("acquia_lift_report_source_{$first_agent}", "/" . $path . '/tests/test_reports.json');
$agent_instance = personalize_agent_load_agent($first_agent);
$report = $agent_instance
->buildCampaignReports(array(
'decision' => 'osid-' . $option_sets[0]->osid,
'start' => $report_start_date,
));
$this
->assertTrue($report['#has_data'], 'Report data file indicates data to show.');
// Now the experiment report should show that Option A has a conversion rate of .19%
$this
->assertEqual("osid-76:Option A", $report['experiment']['reports']['conversion']['reports']['summary']['summary_holder']['summary_table']['#rows'][0]['data'][0]['data']);
$this
->assertEqual("Control", $report['experiment']['reports']['conversion']['reports']['summary']['summary_holder']['summary_table']['#rows'][0]['data'][0]['data-acquia-lift-variation-label']);
$this
->assertEqual("0.19%", $report['experiment']['reports']['conversion']['reports']['summary']['summary_holder']['summary_table']['#rows'][0]['data'][2]['data']);
// The "Winner" flag should appear in the third option's last column, but
// nowhere else.
$this
->assertEqual('<span class="lift-winner">Winner</span>', $report['experiment']['reports']['conversion']['reports']['summary']['summary_holder']['summary_table']['#rows'][2]['data'][5]);
foreach (array(
0,
1,
3,
4,
) as $variation_index) {
$this
->assertEqual('', $report['experiment']['reports']['conversion']['reports']['summary']['summary_holder']['summary_table']['#rows'][$variation_index]['data'][5]);
}
// The report for the second agent should still show the basic report data.
$agent_instance = personalize_agent_load_agent($second_agent);
$report = $agent_instance
->buildCampaignReports(array(
'decision' => 'osid-' . $option_sets[0]->osid,
'start' => $report_start_date,
));
$this
->assertFalse($report['#has_data'], 'Empty report data still indicates no data to show.');
$this
->assertEqual("Option A", $report['experiment']['reports']['conversion']['reports']['summary']['summary_holder']['summary_table']['#rows'][0]['data'][0]['data']);
$this
->assertEqual("Control", $report['experiment']['reports']['conversion']['reports']['summary']['summary_holder']['summary_table']['#rows'][0]['data'][0]['data-acquia-lift-variation-label']);
$this
->assertEqual("0%", $report['experiment']['reports']['conversion']['reports']['summary']['summary_holder']['summary_table']['#rows'][0]['data'][2]['data']);
}
function testReportEndDate() {
$this
->drupalLogin($this->managerUser);
module_load_include('inc', 'acquia_lift', 'acquia_lift.admin');
$agent_name = 'new-test-agent';
$control_rate = 10;
$explore_rate = 30;
$this
->createTestAgent(array(
'name' => $agent_name,
'control_rate' => $control_rate,
'explore_rate' => $explore_rate,
));
// Set the agent up with an option set with 2 options, and a goal, and set it to
// running.
list($option_set, $new_queue_items) = $this
->createOptionSet(0, array(
'agent' => $agent_name,
'plugin' => 'type1',
'option_ids' => array(
'option-1',
'option-2',
),
));
$osid = $option_set->osid;
// Add a goal.
personalize_goal_save($agent_name, 'new-goal', 1);
// 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_name), PERSONALIZE_STATUS_RUNNING);
// Set the started time of the agent to 48 hours ago.
$agent = personalize_agent_load($agent_name);
$started = time() - 48 * 60 * 60;
$agent->started = $started;
personalize_agent_save($agent);
// We need to replicate this test agent on the server so that the errors()
// check will pass.
$test_data = array(
'agents' => array(
array(
'code' => $agent_name,
),
),
'points' => array(
$agent_name => array(
$osid,
),
),
'decisions' => array(
$agent_name => array(
$osid => array(
$osid,
),
),
),
'choices' => array(
$agent_name => array(
$osid => array(
$osid => array(
'option-1',
'option-2',
),
),
),
),
'goals' => array(
$agent_name => array(
// This goal should get deleted upon sync.
'new-goal',
),
),
'reports' => array(
$agent_name => array(
'confidence' => AcquiaLiftTestReports::getBasicConfidenceReport($agent_name),
'targeting-features' => AcquiaLiftTestReports::getBasicTargetingReport($agent_name),
'learning' => array(),
'agent-status' => AcquiaLiftTestReports::getBasicStatusReport($agent_name),
'context-filters' => AcquiaLiftTestReports::getBasicContextFilters(),
),
),
);
variable_set('acquia_lift_web_test_data', $test_data);
$this
->resetAll();
DummyAcquiaLiftHttpClient::clearLoggedRequests();
AcquiaLiftAPI::setTestInstance();
$agent_instance = personalize_agent_load_agent($agent_name);
$form_state = array();
$agent_data = personalize_agent_load($agent_name);
// We call the report generating function and then check the request made to the
// Lift API.
acquia_lift_report_custom(array(), $form_state, $agent_instance, $agent_data, $option_set);
$requests = DummyAcquiaLiftHttpClient::getLoggedRequests();
$start_date = date('Y-m-d', $started);
$now = time();
$end_date = date('Y-m-d', $now);
$confidence_report_uri = $requests[0]['uri'];
$pattern = "/http\\:\\/\\/api\\.example\\.com\\/test\\-owner\\-code\\/{$agent_name}\\/report\\/confidence\\/{$start_date}\\/(\\d{4}\\-\\d{2}\\-\\d{2})/";
$matches = array();
preg_match($pattern, $confidence_report_uri, $matches);
$this
->assertEqual($end_date, $matches[1]);
// Now set the campaign to completed
personalize_agent_set_status($agent_name, PERSONALIZE_STATUS_COMPLETED);
// Specify the completed time as yesterday.
$yesterday = $now - 24 * 60 * 60;
variable_set(_personalize_agent_get_stoptime_variable($agent_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_custom(array(), $form_state, $agent_instance, $agent_data, $option_set);
$requests = DummyAcquiaLiftHttpClient::getLoggedRequests();
$start_date = date('Y-m-d', $started);
$confidence_report_uri = $requests[0]['uri'];
$pattern = "/http\\:\\/\\/api\\.example\\.com\\/test\\-owner\\-code\\/{$agent_name}\\/report\\/confidence\\/{$start_date}\\/(\\d{4}\\-\\d{2}\\-\\d{2})/";
$matches = array();
preg_match($pattern, $confidence_report_uri, $matches);
$this
->assertEqual(date('Y-m-d', $yesterday), $matches[1]);
}
function testPerGoalReport() {
AcquiaLiftAPI::setTestInstance();
$agent = $this
->createTestAgent();
$this
->resetAll();
DummyAcquiaLiftHttpClient::clearLoggedRequests();
// Call the conversion report specifying a particular goal.
$agent
->buildConversionReport(array(
'goal' => 'user_login',
));
$requests = DummyAcquiaLiftHttpClient::getLoggedRequests();
$this
->assertEqual(2, count($requests));
$agent_name = $agent
->getMachineName();
$date = date('Y-m-d');
// Confirm that the report requests made include the goal in the parameters.
$summary_url = "http://api.example.com/test-owner-code/{$agent_name}/report/confidence/{$date}/{$date}?features=&apikey=test-admin-key&confidence-measure=0.95&aggregated-over-dates=true&goal=user_login&policies=explore";
$detail_url = "http://api.example.com/test-owner-code/{$agent_name}/report/confidence/{$date}/{$date}?features=&apikey=test-admin-key&confidence-measure=0.95&aggregated-over-dates=false&goal=user_login&policies=explore";
$this
->assertEqual($summary_url, $requests[0]['uri']);
$this
->assertEqual($detail_url, $requests[1]['uri']);
}
public function testReportDates() {
$this
->drupalLogin($this->managerUser);
AcquiaLiftAPI::setTestInstance();
$agents = array(
'first-agent' => array(
'num_options' => 2,
'num_days' => 12,
),
'second-agent' => array(
'num_options' => 2,
'num_days' => 30,
),
);
module_load_include('inc', 'acquia_lift', 'acquia_lift.admin');
$now = time();
foreach ($agents as $agent_name => &$agent_info) {
$agent_instance = $this
->createTestAgent(array(
'name' => $agent_name,
), TRUE, FALSE);
$agent_name = $agent_instance
->getMachineName();
$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);
$agent = personalize_agent_load($agent_name);
$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. 12 days.
$this
->assertEqual(array(
date('Y-m-d', $now - 12 * 86400),
date('Y-m-d', $now),
), $agents['first-agent']['report_dates']);
// The second agent has been runnign for 60 days but should only show 14.
$this
->assertEqual(array(
date('Y-m-d', $now - 14 * 86400),
date('Y-m-d', $now),
), $agents['second-agent']['report_dates']);
// Now set the max days to 30 instead of 14.
variable_set('acquia_lift_report_max_days', 30);
$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. 12 days.
$this
->assertEqual(array(
date('Y-m-d', $now - 12 * 86400),
date('Y-m-d', $now),
), $agents['first-agent']['report_dates']);
// The second agent should now also show the complete history, i.e. 30 days.
$this
->assertEqual(array(
date('Y-m-d', $now - 30 * 86400),
date('Y-m-d', $now),
), $agents['second-agent']['report_dates']);
}
}
class AcquiaLiftWebTestWorkflow extends AcquiaLiftWebTestBase {
public static function getInfo() {
return array(
'name' => t('Acquia Lift Web Tests - Workflows'),
'description' => t('Tests functionality related to particular campaign 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.
$field = array(
'type' => 'text',
'field_name' => 'article_headline',
'cardinality' => -1,
'settings' => array(
'personalize' => array(
'enabled' => 1,
'agent_type' => 'acquia_lift',
'options' => array(
'acquia_lift' => array(
'control_rate' => 10,
'decision_style' => 'adaptive',
'explore_rate' => 25,
),
),
'create_goal' => 1,
'auto_start' => 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);
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']);
$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']);
$expected_queue_items = array(
array(
'method' => 'saveAgent',
'args' => array(
$agent_name,
'Article: Personalizable Headline 1',
'adaptive',
PERSONALIZE_STATUS_NOT_STARTED,
10 / 100,
25 / 100,
true,
),
'agent' => $agent_name,
),
array(
'method' => 'savePoint',
'args' => array(
$agent_name,
$first_osid,
),
'agent' => $agent_name,
),
array(
'method' => 'saveDecision',
'args' => array(
$agent_name,
$first_osid,
$first_osid,
),
'agent' => $agent_name,
),
array(
'method' => 'saveChoice',
'args' => array(
$agent_name,
$first_osid,
$first_osid,
'first-value',
),
'agent' => $agent_name,
),
array(
'method' => 'saveChoice',
'args' => array(
$agent_name,
$first_osid,
$first_osid,
'second-value',
),
'agent' => $agent_name,
),
array(
'method' => 'saveGoal',
'args' => array(
$agent_name,
$action_name,
),
'agent' => $agent_name,
),
array(
'callback' => 'personalize_agent_set_status',
'args' => array(
$agent_name,
PERSONALIZE_STATUS_RUNNING,
),
),
);
$this
->assertQueueItems($expected_queue_items);
// 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']);
$this->personalizedQueue
->deleteQueue();
// 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));
// We should only have items in the queue for saving the agent and the
// option set.
$expected_queue_items = array(
array(
'method' => 'saveAgent',
'args' => array(
$third_agent,
'Article: Personalizable Headline 3',
'adaptive',
PERSONALIZE_STATUS_NOT_STARTED,
10 / 100,
25 / 100,
true,
),
'agent' => $third_agent,
),
array(
'method' => 'savePoint',
'args' => array(
$third_agent,
$third_osid,
),
'agent' => $third_agent,
),
array(
'method' => 'saveDecision',
'args' => array(
$third_agent,
$third_osid,
$third_osid,
),
'agent' => $third_agent,
),
array(
'method' => 'saveChoice',
'args' => array(
$third_agent,
$third_osid,
$third_osid,
'first-value',
),
'agent' => $third_agent,
),
array(
'method' => 'saveChoice',
'args' => array(
$third_agent,
$third_osid,
$third_osid,
'second-value',
),
'agent' => $third_agent,
),
);
$this
->assertQueueItems($expected_queue_items);
}
/**
* Tests the logic of AcquiaLiftAgent's stopNow() implementation in the
* simplest use case.
*/
function testAutoStop() {
// Create a new agent via the UI.
$agent = $this
->createTestAgent(array(
'control_rate' => 10,
'explore_rate' => 30,
'auto_stop' => 1,
), TRUE, FALSE);
$machine_name = $agent
->getMachineName();
$agent_data = personalize_agent_load($machine_name, TRUE);
// Set the start time of the agent to 2 minutes ago.
$agent_data->started = time() - 120;
// Most basic case - a single option set with 2 options.
list($option_set, $new_queue_items) = $this
->createOptionSet(0, array(
'agent' => $machine_name,
'plugin' => 'type1',
'num_options' => 3,
));
$osid = 'osid-' . $option_set->osid;
// Generate the reporting data to be returned by the dummy http client for this
// agent.
$points = array(
$osid => array(
$osid . ':option-A',
$osid . ':option-B',
$osid . ':option-C',
),
);
$test_data = array(
'reports' => array(
$machine_name => array(
// Generate a fake confidence report with no clear winner.
'confidence' => AcquiaLiftTestReports::generateConfidenceReportWithWinners($machine_name, $points),
),
),
);
variable_set('acquia_lift_web_test_data', $test_data);
// Ensure no other criteria are used to determine whether we should stop.
variable_set('acquia_lift_min_decisions', 0);
variable_set('acquia_lift_min_runtime_num', 0);
$this
->resetAll();
// Make sure we are using a test instance of the API client.
AcquiaLiftAPI::setTestInstance();
$stop = $agent
->stopNow();
// The call should return FALSE as neither minimum runtime nor minimum decisions
// has been configured as a basis on which to stop.
$this
->assertFalse($stop);
// No winner should have been set on the option set.
$option_set = personalize_option_set_load(1, TRUE);
$this
->assertNull($option_set->winner);
// Set min decisions to 30 and we should get option C set as the winner (just
// because the test data is set up to give higher values to later options
// if not otherwise specified.)
variable_set('acquia_lift_min_decisions', 30);
$this
->resetAll();
$agent_instance = personalize_agent_load_agent($machine_name, TRUE);
AcquiaLiftAPI::setTestInstance();
$stop = $agent_instance
->stopNow();
$this
->assertTrue($stop);
// Confirm the winner has been set on the option set.
$option_set = personalize_option_set_load($option_set->osid, TRUE);
$this
->assertEqual('option-C', $option_set->winner);
// Now generate a report where option B has the highest estimated value.
$test_data = array(
'reports' => array(
$machine_name => array(
'confidence' => AcquiaLiftTestReports::generateConfidenceReportWithWinners($machine_name, $points, array(
$osid => $osid . ':option-B',
)),
),
),
);
variable_set('acquia_lift_web_test_data', $test_data);
$this
->resetAll();
AcquiaLiftAPI::setTestInstance();
$agent_instance = personalize_agent_load_agent($machine_name, TRUE);
$stop = $agent_instance
->stopNow();
$this
->assertTrue($stop);
// Confirm the winner has been set on the option set.
$option_set = personalize_option_set_load($option_set->osid, TRUE);
$this
->assertEqual('option-B', $option_set->winner);
// Setting the minimum number of decisions to 100 will mean we won't have enough
// decisions so we should get FALSE.
variable_set('acquia_lift_min_decisions', 100);
$this
->resetAll();
$agent_instance = personalize_agent_load_agent($machine_name, TRUE);
AcquiaLiftAPI::setTestInstance();
$stop = $agent_instance
->stopNow();
$this
->assertFalse($stop);
// Setting it to 30 should get TRUE again.
variable_set('acquia_lift_min_decisions', 30);
$this
->resetAll();
$agent_instance = personalize_agent_load_agent($machine_name, TRUE);
AcquiaLiftAPI::setTestInstance();
$stop = $agent_instance
->stopNow();
$this
->assertTrue($stop);
// Setting the minimum runtime to 1 day should give us FALSE.
variable_set('acquia_lift_min_runtime_num', 1);
variable_set('acquia_lift_min_runtime_unit', 'day');
$this
->resetAll();
$agent_instance = personalize_agent_load_agent($machine_name, TRUE);
AcquiaLiftAPI::setTestInstance();
$stop = $agent_instance
->stopNow();
$this
->assertFalse($stop);
// Setting the minimum runtime to 1 minute should give us TRUE again.
variable_set('acquia_lift_min_runtime_unit', 'minute');
$this
->resetAll();
$agent_instance = personalize_agent_load_agent($machine_name, TRUE);
AcquiaLiftAPI::setTestInstance();
$stop = $agent_instance
->stopNow();
$this
->assertTrue($stop);
}
/**
* Tests the logic of AcquiaLiftAgent's stopNow() implementation when the agent
* has mulitple decision points including an MVT.
*/
function testAutoStopMultiplePoints() {
// Create a new agent.
$agent = $this
->createTestAgent(array(
'control_rate' => 10,
'explore_rate' => 30,
'auto_stop' => 1,
), TRUE, FALSE);
$machine_name = $agent
->getMachineName();
// This time we'll add 3 option sets.
$option_set_values = array(
array(
'agent' => $machine_name,
'plugin' => 'type1',
'num_options' => 3,
),
array(
'agent' => $machine_name,
'plugin' => 'type2',
'num_options' => 2,
),
array(
'agent' => $machine_name,
'plugin' => 'type2',
'num_options' => 3,
),
);
$option_sets = array();
foreach ($option_set_values as $i => $values) {
list($option_set, $new_queue_items) = $this
->createOptionSet($i, $values);
$option_sets[] = $option_set;
}
$first_osid = 'osid-' . $option_sets[0]->osid;
$second_osid = 'osid-' . $option_sets[1]->osid;
$third_osid = 'osid-' . $option_sets[2]->osid;
// Create an MVT and add two of the option sets to it.
$mvt_label = $this
->randomName();
$mvt_machine_name = personalize_generate_machine_name($mvt_label, 'personalize_mvt_machine_name_exists');
$edit = array(
'mvt[add][mvt_basic_info][label]' => $mvt_machine_name,
'mvt[add][mvt_basic_info][option_sets][]' => array(
$option_sets[1]->osid,
$option_sets[2]->osid,
),
);
$this
->drupalPost("admin/structure/personalize/manage/{$machine_name}/edit", $edit, $this
->getButton('mvt'));
// Generate the reporting data to be returned by the dummy http client for this
// agent. All possible choices at each decision point need to be accounted for in
// the report.
$points = array(
$first_osid => array(
$first_osid . ':option-A',
$first_osid . ':option-B',
$first_osid . ':option-C',
),
$mvt_machine_name => array(
$second_osid . ':option-A,' . $third_osid . ':option-A',
$second_osid . ':option-A,' . $third_osid . ':option-B',
$second_osid . ':option-A,' . $third_osid . ':option-C',
$second_osid . ':option-B,' . $third_osid . ':option-A',
$second_osid . ':option-B,' . $third_osid . ':option-B',
$second_osid . ':option-B,' . $third_osid . ':option-C',
),
);
$test_data = array(
'reports' => array(
$machine_name => array(
// We'll specify a winner at each decision point - for option set 1 it will be
// Option B and for the MVT it will be the combination of Option A and Option C
// in Option Sets 2 and 3 respectively.
'confidence' => AcquiaLiftTestReports::generateConfidenceReportWithWinners($machine_name, $points, array(
$first_osid => $first_osid . ':option-B',
$mvt_machine_name => $second_osid . ':option-A,' . $third_osid . ':option-C',
)),
),
),
);
variable_set('acquia_lift_web_test_data', $test_data);
$this
->resetAll();
$agent_instance = personalize_agent_load_agent($machine_name, TRUE);
AcquiaLiftAPI::setTestInstance();
// Set the minimum number of decisions to 30, and the minium runtime to 0 so
// that we know we'll get passed these two checks.
variable_set('acquia_lift_min_decisions', 30);
variable_set('acquia_lift_min_runtime_num', 0);
$this
->resetAll();
$agent_instance = personalize_agent_load_agent($machine_name, TRUE);
AcquiaLiftAPI::setTestInstance();
$stop = $agent_instance
->stopNow();
$this
->assertTrue($stop);
// CHeck that the winner has been set on each option set.
$option_sets = personalize_option_set_load_by_agent($machine_name, TRUE);
$osids = array_keys($option_sets);
$this
->assertEqual('option-B', $option_sets[$osids[0]]->winner);
$this
->assertEqual('option-A', $option_sets[$osids[1]]->winner);
$this
->assertEqual('option-C', $option_sets[$osids[2]]->winner);
// Setting the minimum number of decisions to 70 will mean the first decision point
// won't satisfy this so we should get FALSE from teh stopNow() call.
variable_set('acquia_lift_min_decisions', 70);
$this
->resetAll();
$agent_instance = personalize_agent_load_agent($machine_name, TRUE);
AcquiaLiftAPI::setTestInstance();
$stop = $agent_instance
->stopNow();
$this
->assertFalse($stop);
// Setting it to 60 should get TRUE again.
variable_set('acquia_lift_min_decisions', 60);
$this
->resetAll();
$agent_instance = personalize_agent_load_agent($machine_name, TRUE);
AcquiaLiftAPI::setTestInstance();
$stop = $agent_instance
->stopNow();
$this
->assertTrue($stop);
}
/**
* Tests campaign javascript settings.
*/
function testCampaignSettings() {
module_enable(array(
'personalize_test_extra_agent',
));
$this
->resetAll();
$this
->resetAll();
$admin_user = $this
->drupalCreateUser(array(
'access administration pages',
'manage personalized content',
));
$this
->drupalLogin($admin_user);
// 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');
$second_agent_name = $this
->randomName();
$second_agent_machine_name = personalize_generate_machine_name($second_agent_name, 'personalize_agent_machine_name_exists');
$agents = array(
array(
'label' => $first_agent_name,
'machine_name' => $first_agent_machine_name,
'agent_type' => 'test_agent',
),
array(
'label' => $second_agent_name,
'machine_name' => $second_agent_machine_name,
'agent_type' => 'test_extra_agent',
),
);
foreach ($agents as $agent) {
$edit = array(
'agent_basic_info[title]' => $agent['label'],
'agent_basic_info[machine_name]' => $agent['machine_name'],
'agent_basic_info[agent_type]' => $agent['agent_type'],
);
$this
->drupalPost('admin/structure/personalize/add', $edit, $this
->getButton('agent'));
}
$expected = array(
$first_agent_machine_name => array(
'name' => $first_agent_machine_name,
'label' => $first_agent_name,
'type' => 'test_agent',
'status' => PERSONALIZE_STATUS_NOT_STARTED,
'nextStatus' => array(
'status' => PERSONALIZE_STATUS_RUNNING,
'text' => t('Start'),
),
'links' => array(
'edit' => url('admin/structure/personalize/manage/' . $first_agent_machine_name . '/edit'),
'report' => '',
'view' => url('admin/structure/personalize/manage/' . $first_agent_machine_name),
),
'supportsGoals' => TRUE,
'optionSetTypes' => array(),
'goals' => NULL,
'verified' => TRUE,
),
$second_agent_machine_name => array(
'name' => $second_agent_machine_name,
'label' => $second_agent_name,
'type' => 'test_extra_agent',
'status' => PERSONALIZE_STATUS_NOT_STARTED,
'nextStatus' => array(
'status' => PERSONALIZE_STATUS_RUNNING,
'text' => t('Start'),
),
'links' => array(
'edit' => url('admin/structure/personalize/manage/' . $second_agent_machine_name . '/edit'),
'report' => '',
'view' => url('admin/structure/personalize/manage/' . $second_agent_machine_name),
),
'supportsGoals' => FALSE,
'optionSetTypes' => array(),
'goals' => NULL,
'verified' => TRUE,
),
);
$settings = $this
->drupalGetSettings();
$this
->assertEqual($settings['acquia_lift']['campaigns'][$first_agent_machine_name], $expected[$first_agent_machine_name]);
$this
->assertEqual($settings['acquia_lift']['campaigns'][$second_agent_machine_name], $expected[$second_agent_machine_name]);
// Click the "start" button for the first agent.
$html_id_first_agent = "personalize-change-status-{$first_agent_machine_name}-form";
$this
->drupalPost('admin/structure/personalize', array(), t('Start'), array(), array(), $html_id_first_agent);
// As soon as the agent is started, we are able to access its reports.
$expected[$first_agent_machine_name]['links']['report'] = url('admin/structure/personalize/manage/' . $first_agent_machine_name . '/report');
$expected[$first_agent_machine_name]['status'] = PERSONALIZE_STATUS_RUNNING;
$expected[$first_agent_machine_name]['nextStatus'] = array(
'status' => PERSONALIZE_STATUS_PAUSED,
'text' => t('Pause'),
);
$settings = $this
->drupalGetSettings();
$this
->assertEqual($settings['acquia_lift']['campaigns'][$first_agent_machine_name], $expected[$first_agent_machine_name]);
$this
->assertEqual($settings['acquia_lift']['campaigns'][$second_agent_machine_name], $expected[$second_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]);
$this
->assertEqual($settings['acquia_lift']['campaigns'][$second_agent_machine_name], $expected[$second_agent_machine_name]);
}
/**
* Tests the effect of the acquia_lift_unibar_allow_status_change variable to
* prevent verification checks on every page load.
*/
function testVerificationChecks() {
module_load_include('inc', 'acquia_lift', 'acquia_lift.ui');
AcquiaLiftAPI::setTestInstance();
// Create a bunch of agents.
$num_agents = 10;
for ($i = 0; $i < $num_agents; $i++) {
$this
->createTestAgent(array(
'control_rate' => 10,
'explore_rate' => 30,
));
}
$this
->resetAll();
DummyAcquiaLiftHttpClient::clearLoggedRequests();
$page = array(
'page_top' => array(),
);
acquia_lift_build_page($page);
// There should be 3 requests per agent, and there are 11 agents (the 10 we
// just created plus the default.)
$requests = DummyAcquiaLiftHttpClient::getLoggedRequests();
$this
->assertEqual(count($requests), 3 + 3 * $num_agents);
// Don't clear cache but clear logged requests and call the function again,
// there shouldn't be any new requests.
DummyAcquiaLiftHttpClient::clearLoggedRequests();
acquia_lift_build_page($page);
$requests = DummyAcquiaLiftHttpClient::getLoggedRequests();
$this
->assertEqual(count($requests), 0);
// Clear the cache and confirm they are made again.
$this
->resetAll();
DummyAcquiaLiftHttpClient::clearLoggedRequests();
acquia_lift_build_page($page);
$requests = DummyAcquiaLiftHttpClient::getLoggedRequests();
$this
->assertEqual(count($requests), 3 + 3 * $num_agents);
// Now disable allowing status changes from the unibar.
variable_set('acquia_lift_unibar_allow_status_change', 0);
$this
->resetAll();
DummyAcquiaLiftHttpClient::clearLoggedRequests();
acquia_lift_build_page($page);
$requests = DummyAcquiaLiftHttpClient::getLoggedRequests();
$this
->assertEqual(count($requests), 0);
}
// Tests changing the status of an agent via AJAX.
function testAgentStatusChangeAJAX() {
module_enable(array(
'personalize_test_extra_agent',
));
$this
->resetAll();
// Need to call resetAll again to force ctools to load the class files.
$this
->resetAll();
$admin_user = $this
->drupalCreateUser(array(
'access administration pages',
'manage personalized content',
));
$this
->drupalLogin($admin_user);
// 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');
$second_agent_name = $this
->randomName();
$second_agent_machine_name = personalize_generate_machine_name($second_agent_name, 'personalize_agent_machine_name_exists');
$agents = array(
array(
'label' => $first_agent_name,
'machine_name' => $first_agent_machine_name,
'agent_type' => 'test_agent',
),
array(
'label' => $second_agent_name,
'machine_name' => $second_agent_machine_name,
'agent_type' => 'test_invalid_agent',
),
);
foreach ($agents as $agent) {
$edit = array(
'agent_basic_info[title]' => $agent['label'],
'agent_basic_info[machine_name]' => $agent['machine_name'],
'agent_basic_info[agent_type]' => $agent['agent_type'],
);
$this
->drupalPost('admin/structure/personalize/add', $edit, $this
->getButton('agent'));
}
// Now test the ajax callback.
// Expected case to update to next status.
$expected = array(
'success' => TRUE,
'nextStatus' => array(
'status' => PERSONALIZE_STATUS_PAUSED,
'text' => t('Pause'),
),
'currentStatus' => PERSONALIZE_STATUS_RUNNING,
);
$result = $this
->drupalGetAjax('admin/structure/personalize/manage/' . $first_agent_machine_name . '/ajax_status/' . PERSONALIZE_STATUS_RUNNING);
$this
->assertEqual($expected, $result);
// Try an update that doesn't change the status.
$result = $this
->drupalGetAjax('admin/structure/personalize/manage/' . $first_agent_machine_name . '/ajax_status/' . PERSONALIZE_STATUS_RUNNING);
$this
->assertEqual($expected, $result);
// Try to update an agent that cannot be verified.
$expected = array(
'success' => FALSE,
);
$result = $this
->drupalGetAjax('admin/structure/personalize/manage/' . $second_agent_machine_name . '/ajax_status/' . PERSONALIZE_STATUS_RUNNING);
$this
->assertEqual($expected, $result);
// Try to call the path without the proper permissions.
$this
->drupalLogout();
$this
->drupalGet('admin/structure/personalize/manage/' . $first_agent_machine_name . '/ajax_status/' . PERSONALIZE_STATUS_RUNNING);
$this
->assertText(t('Access denied'));
}
/**
* 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,
);
}
}
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 campaigns.'),
'group' => t('Personalize'),
);
}
public function setUp() {
parent::setUp();
variable_set('acquia_lift_target_enabled', TRUE);
}
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 hte agent.
list($option_set, ) = $this
->createOptionSet(0, array(
'plugin' => 'blocks',
'agent' => $agent->machine_name,
'option_ids' => array(
'first-choice',
'second-choice',
'third-choice',
),
), FALSE);
$this
->resetAll();
$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 = key($option_set->targeting);
$expected_targeting = array(
$audience_name => array(
'label' => $label,
'weight' => 0,
'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');
$this
->assertTrue($saved);
$option_set = personalize_option_set_load($option_set->osid, TRUE);
$audience_names = array_keys($option_set->targeting);
$expected_targeting[$audience_names[1]] = array(
'label' => $label,
'weight' => 1,
'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 testAssignVariations() {
module_load_include('inc', 'acquia_lift', 'acquia_lift.admin');
$agent = $this
->createTargetingAgent();
$this
->assertFalse(isset($agent->data['lift_targeting']));
$this
->resetAll();
list($option_set, ) = $this
->createOptionSet(0, array(
'plugin' => 'blocks',
'agent' => $agent->machine_name,
'option_ids' => array(
'first-choice',
'second-choice',
'third-choice',
),
), FALSE);
$this
->resetAll();
// 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',
),
);
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']);
}
function testImplementTargetingStructure() {
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(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_update_targeting($agent);
// We should have a new nested acquia_lift agent and option set.
$agents = personalize_agent_load_by_type('acquia_lift');
$this
->assertEqual(1, count($agents));
$nested_agent = reset($agents);
$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.
$option_set = personalize_option_set_load($parent_option_set->osid, TRUE);
$this
->assertEqual($nested_osid, $option_set->targeting[$audience_name]['osid']);
// Create a new target audience and change the strucutre of our campaign.
$second_audience = personalize_generate_machine_name($this
->randomName(), NULL, '-');
$this
->createTargetAudience($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],
),
);
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 delete the existing nested
// option set and create a new one.
AcquiaLiftAPI::setTestInstance();
acquia_lift_update_targeting($agent);
$nested_option_set = personalize_option_set_load($nested_osid, TRUE);
$this
->assertFalse($nested_option_set);
// Check the new agent and option set.
$agents = personalize_agent_load_by_type('acquia_lift');
$this
->assertEqual(1, count($agents));
$nested_agent = reset($agents);
$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.
$this
->assertEqual($option_ids[2], $parent_option_set->targeting[$audience_name]['option_id']);
// It should no longer have an osid property.
$this
->assertFalse(isset($parent_option_set->targeting[$audience_name]['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(
$audience_name => array(
$option_ids[0],
$option_ids[1],
),
$second_audience => array(
$option_ids[0],
$option_ids[2],
),
);
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 not delete the existing nested
// option set but it should change the audience it belongs to.
AcquiaLiftAPI::setTestInstance();
acquia_lift_update_targeting($agent);
$nested_option_set = personalize_option_set_load($nested_osid, TRUE);
$this
->assertTrue($nested_option_set);
// We should have two nested agents each with one option set.
$agents = personalize_agent_load_by_type('acquia_lift');
$this
->assertEqual(2, count($agents));
// Find the osid of the new option set so we can check that it has been set
// on the correct target audience.
foreach ($agents as $nested) {
// Find the *new* nested agent.
if ($nested->machine_name != $nested_agent->machine_name) {
$option_sets = personalize_option_set_load_by_agent($nested->machine_name);
$nested_os = reset($option_sets);
$nested_osid2 = $nested_os->osid;
}
}
if (isset($nested_osid2)) {
// Confirm that the correct osid is assigend to each of the two target
// audiences.
$parent_option_set = personalize_option_set_load($parent_option_set->osid, TRUE);
$this
->assertEqual(2, count($parent_option_set->targeting));
foreach (array(
$audience_name => $nested_osid,
$second_audience => $nested_osid2,
) as $audience => $osid) {
$this
->assertEqual($osid, $parent_option_set->targeting[$audience]['osid']);
$this
->assertFalse(isset($parent_option_set->targeting[$audience]['option_id']));
}
}
else {
$this
->fail('Could not find the second option set');
}
}
protected function createTargetingAgent($label = NULL) {
AcquiaLiftAPI::setTestInstance();
if (empty($label)) {
$label = $this
->randomName();
}
$agent = new stdClass();
$agent->label = $label;
$agent->plugin = 'acquia_lift_target';
$agent->data = array();
$agent->machine_name = personalize_generate_machine_name($label, 'personalize_agent_machine_name_exists');
$agent = personalize_agent_save($agent);
$this
->resetAll();
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;
}
}
Classes
Name | Description |
---|---|
AcquiaLiftWebTestAgentAdmin | |
AcquiaLiftWebTestBase | @file Integration tests for Acquia Lift module. |
AcquiaLiftWebTestConfig | |
AcquiaLiftWebTestFundamentals | |
AcquiaLiftWebTestReports | |
AcquiaLiftWebTestTarget | |
AcquiaLiftWebTestVariationSets | |
AcquiaLiftWebTestWorkflow |