AWS Device Farmのデスクトップブラウザテスト機能でVPCエンドポイントを使えるようになりました

2021.11.10

いわさです。

先日のアップデートでAWS Device Farmのデスクトップブラウザテスト機能にてVPCエンドポイントを使えるようになりました。
これによって、従来デバイスファームからアクセスできなかったVPC内のプライベートなWebアプリケーションへアクセスして自動テストを行うことが出来る様になりました。

今回のアップデートはデスクトップブラウザテスト機能のみです。
モバイルデバイステストの対応状況ですが、現在プライベートデバイスについてはVPCエンドポイントの利用が可能です。

なお、共有モバイルデバイスについては本日時点ではVPCエンドポイントは利用できません。

ためしてみる

プライベートAPIの作成

API Gatewayのエンドポイントタイプをプライベートにすると、VPCエンドポイント経由でのみアクセス可能なプライベートなAPIを作成することが出来ます。
また、モック機能を使うことでバックエンドなしで検証用のレスポンスを設定出来るのでこちらを使って検証することにしました。

なお、Device Farmがオレゴン(us-west-2)リージョンでのみ利用可能なので、VPCを始めとするリソース一式はオレゴンリージョンで作成します。

事前にexecute-apiのエンドポイントを作成し、API Gatewayで指定します。

モックは統合レスポンスで適当な値を。

API Gatewayいつも忘れるのですがデプロイが必要なので注意してください。
また、プライベートエンドポイントの場合はリソースポリシーの設定変更が必要ですのでご注意ください。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": "execute-api:/*/*/*",
            "Condition": {
                "StringNotEquals": {
                    "aws:sourceVpc": "vpc-0ce7e82efbb57e2db"
                }
            }
        },
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": "execute-api:/*/*/*"
        }
    ]
}

VPC設定なしでアクセス

ではアクセスしてみましょう。
デスクトップブラウザテストのテストコードや環境の導入方法は以下の記事を参考にします。

import boto3
from selenium.webdriver import Remote
from selenium.webdriver import DesiredCapabilities

class TestClass:
    def setup_method(self, method):
        session = boto3.Session(profile_name="hoge")
        devicefarm_client = session.client("devicefarm", region_name="us-west-2")
        testgrid_url_response = devicefarm_client.create_test_grid_url(
            projectArn="arn:aws:devicefarm:us-west-2:123456789012:testgrid-project:9e6b35de-1a24-4ae0-a007-d4cc63de9278",
            expiresInSeconds=300)
        local_desiredcapabilities = DesiredCapabilities.CHROME
        print(local_desiredcapabilities)
        self.driver = Remote(testgrid_url_response["url"], local_desiredcapabilities)

    # later, make sure to end your WebDriver session:
    def teardown_method(self, method):
        self.driver.quit()

    def test_title(self):
        self.driver.get('https://qj9t3v0s5a.execute-api.us-west-2.amazonaws.com/hogege/')
        self.driver.save_screenshot('no-vpc.png')

テストを実行すると、次のようにERR_NAME_NOT_RESOLVEDでStatus500になりました。
qj9t3v0s5a.execute-api.us-west-2.amazonaws.comの名前解決が出来てない感じでしょうか。

iwasa.takahito@hoge devicefarm % pytest          
==================================================================================== test session starts =====================================================================================
platform darwin -- Python 3.9.4, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: /Users/iwasa.takahito/work/devicefarm
collected 1 item                                                                                                                                                                             

test_hoge.py F                                                                                                                                                                         [100%]

========================================================================================== FAILURES ==========================================================================================
____________________________________________________________________________________ TestClass.test_title ____________________________________________________________________________________

self = <test_hoge.TestClass object at 0x10f9ceee0>

    def test_title(self):
>       self.driver.get('https://qj9t3v0s5a.execute-api.us-west-2.amazonaws.com/hogege/')

test_hoge.py:21: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../.pyenv/versions/3.9.4/lib/python3.9/site-packages/selenium/webdriver/remote/webdriver.py:333: in get
    self.execute(Command.GET, {'url': url})
../../.pyenv/versions/3.9.4/lib/python3.9/site-packages/selenium/webdriver/remote/webdriver.py:321: in execute
    self.error_handler.check_response(response)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <selenium.webdriver.remote.errorhandler.ErrorHandler object at 0x114a00fd0>
response = {'status': 500, 'value': '{"value":{"error":"unknown error","message":"unknown error: net::ERR_NAME_NOT_RESOLVED\\n  (...\n\\tRtlGetAppContainerNamedObjectPath [0x76EE72FD+237]\\n\\tRtlGetAppContainerNamedObjectPath [0x76EE72CD+189]\\n"}}'}

VPC設定ありでアクセス

では、次にVPC設定をして同じテストコードを実行してみましょう。

VPCの設定はマネジメントコンソール上で、Device Farmデスクトップブラウザテスト用のプロジェクトに対して設定を行う形となります。
既存プロジェクトの場合はプロジェクト設定画面から、新規プロジェクトの場合はプロジェクト作成時にオプション設定箇所が表示されます。

VPCとサブネット、セキュリティグループを設定します。
可用性のために複数AZを指定しろと出てきましたが、検証なので無視しました。

ではテスト実行です。

iwasa.takahito@hoge devicefarm % pytest
==================================================================================== test session starts =====================================================================================
platform darwin -- Python 3.9.4, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: /Users/iwasa.takahito/work/devicefarm
collected 1 item                                                                                                                                                                             

test_hoge.py .                                                                                                                                                                         [100%]

================================================================================ 1 passed in 60.23s (0:01:00) ================================================================================

成功しましたね、やった!
キャプチャも確認してみましょう。

モックの挙動の調整も並行してやってしまっており、よくわからないレスポンスになっていると思いますが、API Gatewayの統合レスポンスで設定した内容がちゃんと取得出来ています。

ENIの挙動確認

さいごに、ENIの挙動も確認したのでご紹介します。
プロジェクトにVPC設定を行った時点ではENIは作成されていませんでした。

確認したところローカルからpytestを実行したタイミングで、Device FarmマネージドなENIが新規作成されました。

指定したサブネットで作成されていますね。

そして、テストが終わると数分かけてENIが開放されました。

まとめ

本日は、Device FarmのデスクトップブラウザテストにてプライベートAPIへアクセスさせてみました。
Device Farmの設定としては、マネジメントコンソールでVPCとサブネット、セキュリティグループを設定するだけです。とても簡単でした。

今回はオレゴンリージョンで確認しましたが、VPCピアリングを使うことで東京リージョンのプライベートWebアプリへのアクセスも出来そうですね。
今度試してみたいと思います。

個人的には、モバイルデバイスもWebアプリケーションのモバイル用自動テストに有力だと考えているため、起動時にENIが作成される動きなのであれば、共有モバイルデバイスでもいずれプライベートアクセスが出来るようになるかもと期待したいところです。