本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
本節包含程式碼範例,說明 CloudWatch Synthetics Canary 指令碼的一些可能函數。
Node.js 與 Puppeteer 的範例
設定 Cookie
網站依賴 Cookie 來提供自訂功能或追蹤使用者。透過在 CloudWatch Synthetics 指令碼中設定 Cookie,您可以模擬此自訂行為並進行驗證。
例如,網站可能會顯示 Login (登入) 連結,以重新造訪使用者而不是 Register (登錄) 連結。
var synthetics = require('Synthetics');
const log = require('SyntheticsLogger');
const pageLoadBlueprint = async function () {
let url = "http://smile.amazon.com/";
let page = await synthetics.getPage();
// Set cookies. I found that name, value, and either url or domain are required fields.
const cookies = [{
'name': 'cookie1',
'value': 'val1',
'url': url
},{
'name': 'cookie2',
'value': 'val2',
'url': url
},{
'name': 'cookie3',
'value': 'val3',
'url': url
}];
await page.setCookie(...cookies);
// Navigate to the url
await synthetics.executeStep('pageLoaded_home', async function (timeoutInMillis = 30000) {
var response = await page.goto(url, {waitUntil: ['load', 'networkidle0'], timeout: timeoutInMillis});
// Log cookies for this page and this url
const cookiesSet = await page.cookies(url);
log.info("Cookies for url: " + url + " are set to: " + JSON.stringify(cookiesSet));
});
};
exports.handler = async () => {
return await pageLoadBlueprint();
};
裝置模擬
您可以編寫模擬各種裝置的指令碼,以便您可以大致了解頁面在這些裝置上的外觀和行為。
下列範例模擬 iPhone 6 裝置。如需模擬的詳細資訊,請參閱 Puppeteer 文件中的 page.emulate(options)
var synthetics = require('Synthetics');
const log = require('SyntheticsLogger');
const puppeteer = require('puppeteer-core');
const pageLoadBlueprint = async function () {
const iPhone = puppeteer.devices['iPhone 6'];
// INSERT URL here
const URL = "https://amazon.com";
let page = await synthetics.getPage();
await page.emulate(iPhone);
//You can customize the wait condition here. For instance,
//using 'networkidle2' may be less restrictive.
const response = await page.goto(URL, {waitUntil: 'domcontentloaded', timeout: 30000});
if (!response) {
throw "Failed to load page!";
}
await page.waitFor(15000);
await synthetics.takeScreenshot('loaded', 'loaded');
//If the response status code is not a 2xx success code
if (response.status() < 200 || response.status() > 299) {
throw "Failed to load page!";
}
};
exports.handler = async () => {
return await pageLoadBlueprint();
};
多步驟 API Canary
此範例程式碼示範有兩個HTTP步驟的 API Canary:API針對陽性和陰性測試案例進行相同的測試。傳遞步驟組態,以啟用請求/回應標頭的報告。此外,它會隱藏授權標頭和 X-Amz-Security-Token,因為其中包含使用者憑證。
當此指令碼用作 Canary 時,您可以檢視每個步驟的詳細資訊,以及相關HTTP請求,例如步驟通過/失敗、持續時間和效能指標,例如DNS查詢時間和第一個位元組時間。您可以檢視 Canary 執行的 2xx、4xx 和 5xx 數目。
var synthetics = require('Synthetics');
const log = require('SyntheticsLogger');
const apiCanaryBlueprint = async function () {
// Handle validation for positive scenario
const validatePositiveCase = async function(res) {
return new Promise((resolve, reject) => {
if (res.statusCode < 200 || res.statusCode > 299) {
throw res.statusCode + ' ' + res.statusMessage;
}
let responseBody = '';
res.on('data', (d) => {
responseBody += d;
});
res.on('end', () => {
// Add validation on 'responseBody' here if required. For ex, your status code is 200 but data might be empty
resolve();
});
});
};
// Handle validation for negative scenario
const validateNegativeCase = async function(res) {
return new Promise((resolve, reject) => {
if (res.statusCode < 400) {
throw res.statusCode + ' ' + res.statusMessage;
}
resolve();
});
};
let requestOptionsStep1 = {
'hostname': 'myproductsEndpoint.com',
'method': 'GET',
'path': '/test/product/validProductName',
'port': 443,
'protocol': 'https:'
};
let headers = {};
headers['User-Agent'] = [synthetics.getCanaryUserAgentString(), headers['User-Agent']].join(' ');
requestOptionsStep1['headers'] = headers;
// By default headers, post data and response body are not included in the report for security reasons.
// Change the configuration at global level or add as step configuration for individual steps
let stepConfig = {
includeRequestHeaders: true,
includeResponseHeaders: true,
restrictedHeaders: ['X-Amz-Security-Token', 'Authorization'], // Restricted header values do not appear in report generated.
includeRequestBody: true,
includeResponseBody: true
};
await synthetics.executeHttpStep('Verify GET products API with valid name', requestOptionsStep1, validatePositiveCase, stepConfig);
let requestOptionsStep2 = {
'hostname': 'myproductsEndpoint.com',
'method': 'GET',
'path': '/test/canary/InvalidName(',
'port': 443,
'protocol': 'https:'
};
headers = {};
headers['User-Agent'] = [synthetics.getCanaryUserAgentString(), headers['User-Agent']].join(' ');
requestOptionsStep2['headers'] = headers;
// By default headers, post data and response body are not included in the report for security reasons.
// Change the configuration at global level or add as step configuration for individual steps
stepConfig = {
includeRequestHeaders: true,
includeResponseHeaders: true,
restrictedHeaders: ['X-Amz-Security-Token', 'Authorization'], // Restricted header values do not appear in report generated.
includeRequestBody: true,
includeResponseBody: true
};
await synthetics.executeHttpStep('Verify GET products API with invalid name', requestOptionsStep2, validateNegativeCase, stepConfig);
};
exports.handler = async () => {
return await apiCanaryBlueprint();
};
Python 和 Selenium 範例
以下範例 Selenium 程式碼是一個在未載入目標元素時失敗並顯示自訂錯誤訊息的 Canary。
from aws_synthetics.selenium import synthetics_webdriver as webdriver
from aws_synthetics.common import synthetics_logger as logger
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
def custom_selenium_script():
# create a browser instance
browser = webdriver.Chrome()
browser.get('https://www.example.com/')
logger.info('navigated to home page')
# set cookie
browser.add_cookie({'name': 'foo', 'value': 'bar'})
browser.get('https://www.example.com/')
# save screenshot
browser.save_screenshot('signed.png')
# expected status of an element
button_condition = EC.element_to_be_clickable((By.CSS_SELECTOR, '.submit-button'))
# add custom error message on failure
WebDriverWait(browser, 5).until(button_condition, message='Submit button failed to load').click()
logger.info('Submit button loaded successfully')
# browser will be quit automatically at the end of canary run,
# quit action is not necessary in the canary script
browser.quit()
# entry point for the canary
def handler(event, context):
return custom_selenium_script()