woshidan's blog

あいとゆうきとITと、とっておきの話。

xcodebuild testのテスト対象のデバイスやテストケースをappiumぽく簡単に指定できるラッパースクリプトを書いてみた

この記事はiOS2 Advent Calendar 2017の3日目の記事です。

xcodebuild testのテスト対象のデバイスやテストケースをややappiumみたいに簡単に指定できるラッパースクリプトを書いてみました。 なお、CocoaPodsでライブラリ管理をしているプロジェクトを対象としています。CocoaPodsをご利用でない場合は、適宜 -workspace-project オプションに読み替えていただけると幸いです。

スクリプト

スクリプト本体 xcode-wrapper.sh

#!/bin/bash

# configuration for project, written here
WORKSPACE="ExmapleApp.xcworkspace"
APP_SCHEME="ExmapleApp"
TEST_SCHEME="ExmapleAppTests"
BUILD_CONFIG="Debug"

# configuration for test target device written in caps.json
TARGET_LABEL=$(jq .target < ./caps.json)
DEVICE_NAME=$(jq .[$TARGET_LABEL]."deviceName" < ./caps.json | tr -d '"')
PLATFORM_VERSION=$(jq .[$TARGET_LABEL]."platformVersion" < ./caps.json | tr -d '"')
DEVICE_ID=$(jq .[$TARGET_LABEL]."udid" < ./caps.json | tr -d '"')
DEVICE_TYPE=$(jq .[$TARGET_LABEL]."type" < ./caps.json | tr -d '"')

build() {
  if [ "$DEVICE_TYPE" = "simulator" ]
  then
    # refs: https://qiita.com/roothybrid7/items/19f0aeeee98573dab2a6
    xcodebuild \
      -sdk iphonesimulator \
      -destination "platform=iOS Simulator,name=${DEVICE_NAME},OS=${PLATFORM_VERSION}" \
      -configuration "$BUILD_CONFIG" \
      -workspace "$WORKSPACE" -scheme "$APP_SCHEME" \
      build
  else
    xcodebuild \
      -sdk iphoneos \
      -destination "platform=iOS,id=${DEVICE_ID}" \
      -configuration "$BUILD_CONFIG" \
      -workspace "$WORKSPACE" -scheme "$APP_SCHEME" \
      build
  fi
}

test() {
  if [ "$DEVICE_TYPE" = "simulator" ]
  then
    xcodebuild -workspace $WORKSPACE \
      -scheme "$TEST_SCHEME" \
      -sdk iphonesimulator \
      "$TEST_CASE_OPTION" \
      -destination "platform=iOS Simulator,name=${DEVICE_NAME},OS=${PLATFORM_VERSION}" test
  else
    xcodebuild -workspace $WORKSPACE \
      -scheme "$TEST_SCHEME" \
      -sdk iphoneos \
      "$TEST_CASE_OPTION" \
      -destination "platform=iOS,id=${DEVICE_ID}" test
  fi
}

if [ $1 == "build" ]; then
    build
fi

if [ $1 == "test" ]; then
    i=1
    for OPT in "$@"
    do
        if [ $OPT = "-test" ]; then
            TEST_CASE_OPTION="-only-testing:${TEST_SCHEME}/${@:$(expr $i + 2):1}"
            test
            exit 0
        fi
        i=$(expr $i + 1)
    done
    test
fi

設定ファイル caps.json

"target" の部分を変更してテストを実行するデバイスを切り替えます。

{
  "target": "iPhone5", // テストで使うデバイスの指定
  "iPhone5": {
    "type": "simulator", // シミュレータ
    "deviceName": "iPhone 5",
    "platformVersion": "9.3",
    "udid": "" // シミュレータの指定では使わない
  },
  "iPhone6": {
    "type": "simulator", // シミュレータ
    "deviceName": "iPhone 6",
    "platformVersion": "10.0",
    "udid": "" // シミュレータの指定では使わない
  },
  "iPhone7": {
    "type": "simulator", // シミュレータ
    "deviceName": "iPhone 7",
    "platformVersion": "11.1",
    "udid": "" // シミュレータの指定では使わない
  },
   "iPad": {
    "type": "iphoneos", // 実機
    "deviceName": "woshidanのiPad", "" // 実機の指定では使わない
    "platformVersion": "10.3",
    "udid": "DUMMY_ID"
  }
}

使用例

# 全てのテストを実行する
$ ./xcode-wrapper.sh test

# ExmapleTestクラスにおいたテストをすべて実行する
$ ./xcode-wrapper.sh test -test ExmapleTest

# ExmapleTestクラスにおいたテストメソッドtestAを実行する
$ ./xcode-wrapper.sh test -test ExmapleTest/testA

# アプリをビルドする
$ ./xcode-wrapper.sh build

補足

実行されるテストを指定したい

CLIから見守るだけとはいえ、毎回全てのテストを実行するのは時間がかかります。 xcodebuild test サブコマンドは only-testing オプションを用いることで実行するテストを指定することができます。

https://stackoverflow.com/questions/39427263/how-to-use-xcodebuild-with-only-testing-and-skip-testing-flag

上記スクリプトでは、-test オプションを指定することで only-testing オプションで指定する文字列を与えることができます。スクリプト自体は -test オプションなしでも利用可能で、その場合は全てのテストを実行します。

利用できるデバイスの名前やID, OSバージョンの組み合わせについて

caps.json に書くシミュレータや実機デバイスの名前、OSバージョン、IDなどがわからない場合はXCodeAdd Simulators ... の画面か $ instruments -s devices コマンドより確認できます。

XCodeのデバイス管理画面から

f:id:woshidan:20171202232044p:plain

ターミナルから

$ instruments -s devices
...
iPhone SE (10.0) [7DB19BC4-5A56-4D40-93BD-90F551713043] (Simulator)
iPhone SE (10.3.1) [10FE1E72-D129-4593-A18B-AE85F4D9DC78] (Simulator)
iPhone SE (11.1) [C511B853-09C3-4599-A88F-737296F02DED] (Simulator)
iPhone X (11.1) [95022FBF-DDDB-46A8-8978-0129C0A6142D] (Simulator)
...

もっと色々書こうかと思ったのですが力尽きたので現場からは以上です。

XCode Tools CLIのバージョンアップとビルドに必要なパラメータ、権限の変化について

お仕事の都合で古いOSに対してもXCode Tools CLIを使ってビルドする必要があって調べてみても要領を得なかったんだけど少しわかった気がするので、わかったところまで整理してみます*1

アプリとして実機やシミュレータにインストールできるファイルの種類について

説明
.app xcrun simctl を経由して iPhone simulatorへインストールできる。 xcodebuild build コマンドやXCodeでシミュレータへ向けてビルドすることで作成可能
.ipa アプリストアへリリースしたり、実機へデプロイするときに作成する必要があるファイル形式。 .app.xcarchive ファイルから開発者の証明書を何らかの形でアタッチするようなプロセスを経て作成

参考

XCode7時代の .ipa 作成方法とXCode8時代の .ipa 作成方法

  • XCodeが7の頃は .ipa 作成に関して .app ファイルを渡せば xcrunPackageApplication がうまくやってくれていた
  • XCode8.3. で PackageApplication が廃止されてしまった
    • XCode8.3.2 を使う場合 xcrun: error: unable to find utility "PackageApplication", not a developer tool or in PATH というメッセージが出るようになっている
  • このため、 xcrun PackageApplication の代わりに xcodebuild archive を使う必要がある
    • xcodebuild.xcarchive を作成した後、 .ipa を作成する際に exportProvisioningProfile などを自分で設定する必要がある
    • これの具体的なパス (SampleXXX的なノリなのではなく 'MyMobileApp Distribution Profile' みたいなのりでファイル名などが想像しにくい例が多い) がよくわからなくてつらい

参考

XCode 8.2 -> XCode 8.3 で Automatically manage signing が有効になっているプロジェクトにおいて .ipa へのエクスポートが失敗するように

  • [試せていない] exportOptions.plistmethod の値が development でない場合、XCodeでビルドしているときに、ログインしているアカウントが Admin でない場合、、証明書(開発者登録. キーチェーンに登録している) と Provisioning Profile (開発者とappIdに紐づいている) が揃っていても権限がたりなくて export に失敗する
    • [試せていない] CI用にadminにする?
  • [試せていない] xcodebuild -exportArchive -exportOptionsPlist /PATH/exportOptions.plist で指定する exportOptions.plistmethod の値を development にすればうまくいくかも?
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>method</key>
    <string>development</string>
    <key>teamID</key>
    <string>GLPGBQ39X8</string>
</dict>
</plist>

参考

どうすればいいかわかったら今後追記しますが、詳しい人教えて欲しい感じです。

*1:上長許可あり

ERBとCSVを使って簡単な自分用ドリルを作る

最近シェルの勉強をしたいんですが、以前SQLを勉強した時のように基本的なシェルを反復して書くのが一番では? と思って、ドリルのようなものが欲しくなりました。

そこで、CSVにお題とお題の答えを書き連ねたらアコーディオンで答えを出したり隠したりしてくれるHTMLを出すコードと、そのHTMLを見るアプリ*1を書いたのでポスト。

github.com

使い方は、

$ ruby generator/generator.rb input.csv > drill.html

を実行して drill.html をブラウザで開く、です。アプリで見る場合はさらに

$ cp drill.html cp drill.html CSDriller/app/assets/drill.html

とした後、一緒についているAndroidプロジェクトをビルドしてください。

実際動かしてみると下記のような感じです。

参考

qiita.com

特に上記記事のアコーディオンがよすぎて作りたくなったので多謝。

*1:といってもAndroidのWebViewに突っ込むだけ

Cocos2d-x 2.2.6をMac OS Sierraで動くようにするまでのメモ

仕事でやってて面白かったので許可を取って公開。

環境

スクリーンショット 2017-10-19 13.30.52.png (44.2 kB)

メモ

プロジェクトの作成

python create_project.py -project MyGame -package com.MyCompany.AwesomeGame -language cpp

Eclipse インストーラからJavaIDEをインストールして環境変数を設定

  • Help > Install New SoftWare
    • Work with の欄に https://dl-ssl.google.com/android/eclipse を入力
      • Developer Tools をダウンロード
      • Eclipseを再起動
      • DLしたらどこのAndroid SDK を使うか聞かれるので Andorid Studioで使っているパス /Users/woshidan/Library/Android/sdk あたりでも答えておく (設定した値は Preferences > Android からでも確認可能. Android SDKのバージョンが v26 以上なら後の方に書くようにEclipse用に別途古いAndroid SDKを用意した方が良い)

cocos2dxのプロジェクトをインポートとプロジェクト間の依存関係の設定

  • Import > Andorid > Existing Android Code Into Workspacecocos2d-x-2.2.6/cocos2dxplatform/andorid/java をインポート
    • Copy projects into workspace にチェックしておく
  • Import > Andorid > Existing Android Code Into Workspacecocos2d-x-2.2.6/cocos2dx/ProjectName をインポート
    • Copy projects into workspace にチェックしない
    • ProjectName のAndroidManifest.xml 中の minSDKVersion が小さすぎるので14くらいにあげておく
  • PackageManager 上で ProjectName の上を右クリックして Properties > Android を開き、Libraryのところで、libcocos2dxを指すよう設定する
    • isLibrary のチェックはしない(アプリプロジェクトにisLibraryのチェックをするとapkが生成されない)

アプリ側のプロジェクトのLinked Resourcesの修正

  • プロジェクトのところで右クリックして Properteis > Resources > Linked ResourcesLinked Resources のタブを確認。Classes, cocos2dx, extensions, scropting の壊れているパスを修正

古めのNDKを用意してNDK_ROOTの環境変数を設定

  • 古めのNDK(Android NDK, Revision 10e)を https://developer.android.com/ndk/downloads/older_releases.html からDL
    • EclipsePreferences > Android > NDK の項目の NDK LocationにDLしてきたNDKを配置したパスを書く
  • Preferences > Android > NDK に設定したパスが Eclipse に見えてないことがあるので C/C++ > Build > Environment にも NDK_ROOT として追加
  • Bulid Project した結果、 build_native.sh は走ってくれたが。。

トラブルシューティング

Could not find BuildTest.apk! ...

Unknown error: Unable to build: the file dx.jar was not loaded from the SDK folder!

Eclipse起動時に Failed to get the required ADT version number from the SDK

エミュレータを起動しようとしたら[Start]が押せず詳細を確認したら Google Nexus 5X No longer exists as a device

Description Resource Path Location TypeThe container 'Android Dependencies' references non existing library'cocos2d-x-2.2.6/cocos2dx/platform/android/java/bin/libcocos2dx.jar' ...

  • http://renkaze.seesaa.net/article/405756568.html
  • libcocos2xd のプロジェクトで jar を吐き出すパスが別のパスに設定されている
  • libcocos2dx のプロジェクトで右クリックして Properties > Java Build Path < Source の下側の Default output folderlibcocos2dx/bin/classes に設定

java.lang.IllegalArgumentException: No configs match configSpec というエラーでエミュレータで起動するとクラッシュする

Eclipseエミュレータを起動しようとしたら PANIC: Missing emulator engine program for 'arm' CPUS... と出る

Google Nexus 5X no longer exists as a device とでて Nexus 5 のスキンのエミュレータがつけない

まとめ

そろそろEclipseAndroidを開発するのをやめたほうがいいのでは。

現場からは以上です。

ウェブオペレーション サイト運用管理の実践テクニックを読んだ

ウェブオペレーション ―サイト運用管理の実践テクニック (THEORY/IN/PRACTICE)

ウェブオペレーション ―サイト運用管理の実践テクニック (THEORY/IN/PRACTICE)

前職で研修に使われていた記憶があり、いい本なのかなーと思って読みました。 運用系の仕事をしているわけではないので、一ヶ月強かけてなんとか読みおおせた感じです。

各章はかなり生き生きとした文章で、場合によっては「これはもしかして飲み会の書き起こしではないだろうか」「これ開発者の前に出したらグーパンされても文句言えないのでは」と感じた章もいくつかあり、いんたーねっつの進歩を体感することができます。

なんとか読みおおせた印象としては

  • ウェブサービスのサーバ構成について、それぞれのサーバの大まかなイメージが頭に描けるようになった
    • リバースプロキシで静的ファイルを返したりロードバランサの役目もさせて負荷分散をする、一回取得したデータをキャッシュにつっこんで奥のDBにリクエストがいかないようにする、リクエストが大量に来てキャッシュが切れた時DBにリクエストが殺到してダウンする、みたいな
  • 結構前の章でいいよって言われていることが次の章でそうでもないよって言われてたりして、道具を使ったり人の意見を採用する前に要件を確認するのは大事だな、と思えた
  • もともとあまりシェルになじみのない人でなんでもLL言語+RDBMSで考えがちだったのですが、監視のシステムの実装例でawkなどが出てきたり、道具の得意分野に合わせていろんな道具を操ることについて考えさせられた
  • Dynamoの論文の特徴が面白かった
    • Consistent hash, read repair, hinted handoffが書いてあったよと紹介されていて、特に気になったのは read repair.
  • 高可用性(リクエストがあったらいつでも応答できる)と応答速度/パフォーマンス(速くレスポンスが返ってくる)と一貫性(データに矛盾が生じない)が違う、相反しない、という例がくどくどと書かれていて身にしみた
    • 分割耐性はまだ自信がない
  • みんな結構データセンタや社内システムの外からファイアウォールping弾かれてて面白かった
  • サーバの監視システムについて、死活監視・リソース監視(Nagiosなど)・それらの結果の表示(Cacti, Muninなど)、みたいなソフトごとの得意領域があるんだなみたいなイメージが湧いた
  • レスポンスの配信の節で、サーバとクライアントの間に一度に取得できるオブジェクト数の上限があるということを知らなかったため、デバッグコンソールを眺めてみたり

でした。

個人的に特に面白かったのは、6章、9章、12章、15章。

6章の学生時代のサイト運営経験から右往左往しながらシステムを運用していく様子に共感を覚え、9章の急増したトラフィックへの障害対応の文章を読んでリクエストがどのサーバに順に到達するかのイメージを描き、12章でこの人本当にMySQL好きなんだなという気持ちになり*1、15章で高分散型*2NoSQLの監視ソフトウェアの違いや比較的小さい規模で動かすものと大きい規模で動かすものの思想の違いに思いを馳せたり。。

運用経験のない人が一人で読むとどうなのかな、と思いつつ、ここで紹介されている技術は今の時代ではそれなりに枯れていたり廃れていたり流行っていたりするためインターネットにまとめられた記事を適宜参照しながら進めました。しかしまあ、早口でまくしたてるクセがある他部署の先輩の運用談義を聞かされている風味もあり、本開いてる間はなんだか忙しかったのでした...。

前述の文体が気になる点や2011年出版でやや古いところもあるので、この本のポジションに収まる新しい本とかあったらそちらも読んでみたいです。

現場からは以上です。

*1:MySQLコンサルタントの方が書いてるのでそりゃそーだって話なんだけど、これだけMySQL好きな人になら一回コンサルされたいなという感じでした

*2:いまの言い方だとビッグデータ用?

Athenaでクエリの実行結果を使い回すために最近投げたクエリとそのquery_execution_idを記録する

Amazon Athena では

S3上にあるファイルをスキャンした量に応じた料金 + S3をスキャンするためにGETしたリクエスト数(+ファイル容量)

に応じて課金されます。

また、Athenaでは一回SQLを実行した時に query_execution_id が発行され、同じ query_execution_id を使って GetQueryResultsAPIに複数回リクエストを送ると二回目以降は一回目の実行結果が再利用され、新しいクエリは実行されません*1

このため、一度検索した結果が使い回せるのであれば、 query_execution_id を控えておいて結果を再利用した方が良いです。

というわけで、雑に CSV で直近で実行した クエリquery_execution_id の対応を控えておいて、実行しようとしたクエリがすでに実行済みであれば教えてくれるスクリプトを書いたのでポスト。

gem にしようかと思ったけどそれほど大きくなかったのでひとまずこれで。

# athena_query_keeper.rb
require "csv"

class AthenaQueryKeeper
  def initialize(csv_path, keepe_count=20)
    @csv_path = csv_path
    @keepe_count = keepe_count
    @keeped_queries = []

    begin
      CSV.foreach(@csv_path) do |row|
        @keeped_queries.push({ time: row[0], execution_id: row[1], query_string: row[2] })
      end
    rescue Exception => ex
      puts ex
      puts "query keeped csv(path=#{csv_path}) was not found or format was broken."
      puts "new csv will be created."
    end
  end

  def keep(excution_id, query_string)
    if @keeped_queries.count >= @keepe_count
      @keeped_queries.slice!(0, @keeped_queries.count + 1 - @keepe_count)
    end

    @keeped_queries.push({ time: Time.now.to_i, execution_id: excution_id, query_string: query_string })
    flush
  end

  def flush
    CSV.open(@csv_path, 'w') do |csv|
      @keeped_queries.each do |query|
        csv << [ query[:time], query[:execution_id], query[:query_string] ]
      end
    end
  end

  def keeped_execution_id_for(query_string)
    keeped_query = @keeped_queries.find { |query| query[:query_string] == query_string }

    if keeped_query.nil?
      puts "query: #{query_string.slice(0, 60)} ... has been not executed recently."
      ""
    else
      puts "query: \"#{query_string.slice(0, 60)} ... \" has been executed recently."
      puts "you should reuse that result unless the result update must be used."
      keeped_query[:execution_id]
    end
  end
end
# test.rb
require 'aws-sdk-athena'
require "#{File.dirname(__FILE__)}/athena_query_keeper.rb"

query_string = ARGV[0]
client = Aws::Athena::Client.new

begin
  query_execution_id = nil
  athena_query_keeper = AthenaQueryKeeper.new("./sample.csv", 20)
  keeped_query_id = athena_query_keeper.keeped_execution_id_for query_string
  if keeped_query_id.empty?
    start_query_response = client.start_query_execution({
        query_string: query_string,
        query_execution_context: {
           database: "mydatabase",
        },
        result_configuration: {
          output_location: "s3://example-woshidan-test/athena_query_result"
        },
    })

    sleep(3)

    query_execution_id = start_query_response.query_execution_id
    athena_query_keeper.keep(query_execution_id, query_string)
  else
    puts "reuse query result for id=#{keeped_query_id}."
    query_execution_id = keeped_query_id
  end

  puts "query_execution_id: #{query_execution_id}"

  get_query_response = client.get_query_results({
    query_execution_id: query_execution_id
  })

  get_query_response.inspect
rescue Aws::Athena::Errors::InvalidRequestException => ex
  puts ex.inspect
ensure
  puts "query request ended."
end
$ ruby test.rb 'SELECT * FROM mydatabase."athena_logs_20171003_app" WHERE user_id = "tester" LIMIT 10;'
query: SELECT * FROM mydatabase."athena_logs_20171003_app" WHERE us ... has been not executed recently.
result_csv_file_key: 32e86285-e0c5-4329-973d-38bd039945e4
#<Aws::Athena::Errors::InvalidRequestException: Query did not finish successfully. Final query state: FAILED>
query request ended.

$ ruby test.rb 'SELECT * FROM mydatabase."athena_logs_20171003_app" WHERE user_id = "tester" LIMIT 10;'
query: "SELECT * FROM mydatabase."athena_logs_20171003_app" WHERE us ... " has been executed recently.
you should reuse that result unless the result update must be used.
reuse query result for id=32e86285-e0c5-4329-973d-38bd039945e4
result_csv_file_key: 32e86285-e0c5-4329-973d-38bd039945e4
#<Aws::Athena::Errors::InvalidRequestException: Query did not finish successfully. Final query state: FAILED>
query request ended. 

参考

*1:管理画面のHistoryなどで確認できます

AWS CLIでAWS Athenaのクエリがデータベースが見つからないためになんども失敗する場合は結果出力先のS3のバケットのregionを確認する

俺の屍を越えていけ、的なメモ。

require 'aws-sdk-athena'
client = Aws::Athena::Client.new

begin 
    start_response = client.start_query_execution({
      query_string: "SELECT * FROM samples limit 10",
      query_execution_context: {
        database: "mydatabase",
      },
      result_configuration: {
        output_location: "s3://sample-woshidan-test-tokyo/athena_query_result"
      },
    })

  sleep(5)

    result_response = client.get_query_results({
        query_execution_id: start_response.query_execution_id
    })
rescue Aws::Athena::Errors::InvalidRequestException => ex
  puts ex.inspect
ensure
  puts "Ensure"
end

上記のコードで aws-sdk-athena でAthena のクエリを飛ばそうとしたら

Query did not finish successfully. Final query state: FAILED (Aws::Athena::Errors::InvalidRequestException)

というエラーが出て失敗する。なんで失敗したのかさっぱりわからないので、CLIで実行し直すと、

$ aws athena start-query-execution \
>  --query-string "SELECT * FROM mydatabase.samples limit 10;" \
>  --result-configuration OutputLocation=s3://sample-woshidan-test/athena_query_result
{
    "QueryExecutionId": "f8e45456-238a-44ba-955a-40f048e5c3b2"
}

$ aws athena get-query-execution --query-execution-id f8e45456-238a-44ba-955a-40f048e5c3b2
{
    "QueryExecution": {
        "Status": {
            "SubmissionDateTime": 1506675885.243, 
            "State": "FAILED", 
            "CompletionDateTime": 1506675885.387, 
            "StateChangeReason": "com.facebook.presto.hive.DataCatalogException: Namespace mydatabase not found. Please check your query."
        }, 
        "Query": "SELECT * FROM mydatabase.logs limit 10", 
        "Statistics": {
            "DataScannedInBytes": 0, 
            "EngineExecutionTimeInMillis": 53
        }, 
        "ResultConfiguration": {
            "OutputLocation": "s3://sample-woshidan-test/athena_query_result/f8e45456-238a-44ba-955a-40f048e5c3b2.csv"
        }, 
        "QueryExecutionId": "f8e45456-238a-44ba-955a-40f048e5c3b2"
    }
}

というメッセージが出て、どうも database が見つからないらしい。

もしかして、 AWS のアカウントの region を間違ったかな、とAWS CLIの設定で使う region を Athenaの管理画面で表示されている region に設定しなおしてみると

f:id:woshidan:20170929195730p:plain

- region = ap-northeast-1
+ region = us-east-2
The S3 location provided to save your query results is invalid. Please check your S3 location is correct and is in the same region and try again. If you continue to see the issue, contact customer support for further assistance.

戻すと

+ region = ap-northeast-1
- region = us-east-2
Query did not finish successfully. Final query state: FAILED (Aws::Athena::Errors::InvalidRequestException)

どっちに設定しても何かしらダメっぽい...

最終的に

自分がAthenaのクライアントとして選んだ aws-athena-client はその実装でAWS CLIを利用しています。

そして、AWS CLIで設定値として使うregion は ~/.aws/config で指定しているためか

  • クエリを投げるAthenaのデータベースが ~/.aws/config で指定したregionに存在すること
  • クエリ結果の出力先のS3のバケットが ~/.aws/config で指定したregionに存在すること

の2点がAWS CLIでAthenaにクエリを投げるためには必要みたいです。そして最終的に結果出力先のS3のバケットのregionをAthenaのデータベースのregionに揃えてことなきを得ました。

AthenaのクエリでスキャンするS3のバケットのregionは、AWS CLIで使うIAMアカウントがアクセス権を持ってさえいればAthenaのデータベースのregionと違ってもクエリが実行できるのもあっていまいち原因がわからず焦りました。

もしかしたらAthena - S3 間だけでなく、複数のAWSのサービスが協調して動く場合、CLIが一個しかregionの値を持たない、みたいなことが原因で似たようなトラブルはあるかもなと思いつつ、現場からは以上です。