---
# System prepended metadata

title: 光耀 の ClusterFuzz Backlog

---


# Fuzz 紀錄

<div style="font-size:36px;text-align:center;">Fuzz 紀錄</div>
<div style="font-size:18px;text-align:center;">2021.10.06 - 202x.xx.xx</div>

## 團隊
* [楷融學長的 Fuzz 紀錄](https://hackmd.io/@jPlUJwcKR0WwIAB8RN5rcw/rkrxRv-w5) 
* [莊永的 Fuzz 紀錄](https://hackmd.io/@s8952889/ryci1Un02)
* [建澄的 Fuzz 紀錄](https://hackmd.io/haIdRAEhTYyFKApgDUFqXw)
* [祐清的 Fuzz 紀錄](https://hackmd.io/t1b2S2PcTiemo6iHYNTAKg)
* [俊陞的 Fuzz 紀錄](https://hackmd.io/@YAMERO/S1vc_wQAn)

## 相關連結
* [ClusterFuzz](https://google.github.io/clusterfuzz/)
* [google/clusterfuzz](https://github.com/google/clusterfuzz)
* [ntutselab/clusterfuzz](https://github.com/ntutselab/clusterfuzz)
* [Fuzz 紀錄 2022](https://hackmd.io/@kyL/Fuzz2022)

## 2023/01/29
* 嘗試解決 Proxmox VM 與外部 server 之間互連問題
  * 問題：目前外部 Server 使用 OpenVPN 連進內網，外部 Server 去 ping VM 沒問題，但反過來卻出現問題。
  * 網路架構：
    ![image](https://hackmd.io/_uploads/SJHkT2vca.png)
  * 疑點：透過 Mikrotik sniffer 捕抓 package 發現 VM ping 外部 server 的 dst 被導向另一個 IP！
    * 外部 Server ping VM : 
      ![image](https://hackmd.io/_uploads/H1KIp3P9a.png)
    * VM ping 外部 Server
      ![image](https://hackmd.io/_uploads/r15Ka2w5T.png)



## 2023/01/22
啟動另一台伺服器，並與另一台伺服器做 Cluster，讓使用者可以更好地操作
![image](https://hackmd.io/_uploads/S1snPTV56.png)

## 2023/01/08
啟動一台伺服器，使用 Proxmox VE 192.168.14.210:8006

### OpenVPN
* 下載 [OpenVPN <font color="red">特定版本 v2.5.8(重要)</font>](https://openvpn.net/community-downloads/)，否則會連不上！！！找不到的話可點擊[此處](https://swupdate.openvpn.org/community/releases/OpenVPN-2.5.8-I604-amd64.msi)
* 把以下設定檔設定至 OpenVPN 設定檔 :
  ```=
  client
  dev tun
  proto tcp
  remote 140.124.183.112 1194
  keepalive 10 120
  auth SHA1
  auth-user-pass
  cipher AES-256-CBC
  verb 5
  redirect-gateway def1
  <ca>
  -----BEGIN CERTIFICATE-----
  MIIDmzCCAoOgAwIBAgIUOOEMFFT+l7YhSmWRNv7w60USQk0wDQYJKoZIhvcNAQEL
  BQAwXTELMAkGA1UEBhMCVFcxDzANBgNVBAgMBlRhaXBlaTEPMA0GA1UEBwwGVGFp
  cGVpMQ0wCwYDVQQKDAROVFVUMQ0wCwYDVQQLDARDU0lFMQ4wDAYDVQQDDAVTRUxB
  QjAeFw0yNDAxMDgxMDM5MDFaFw0yNTAxMDcxMDM5MDFaMF0xCzAJBgNVBAYTAlRX
  MQ8wDQYDVQQIDAZUYWlwZWkxDzANBgNVBAcMBlRhaXBlaTENMAsGA1UECgwETlRV
  VDENMAsGA1UECwwEQ1NJRTEOMAwGA1UEAwwFU0VMQUIwggEiMA0GCSqGSIb3DQEB
  AQUAA4IBDwAwggEKAoIBAQDY83Kj5bigWSa23XfJh0L2kQdxVwCyUjWfJ0NBdEOR
  VXK9uv/2UGajY//zxsKF+tFSYUo8pPhVN6EW0Fw2EGMdzyPi1DlEccQS6/8azlBl
  ZsVedHGT7DwkFF7sTaboFPkSLXwG9FlwnRP+ZerSkcKvwH3AT8kFWuLmb8Er4Ujd
  7D1dq7cRqsbRXRtACxkSmMms0T/zcrQl2VjXboESCyqNZIfse5qRZIZ7zGzIqZcS
  DJj1df+/N+XYvOBjYuVubSEdQlrqu2d4pWNr27Jc3kwaNpnfUefCn61Mwt44M7Hb
  R0y0BQTBAVrB1LOLf2MnnjNqRb8bR1OaD/xYJGz1s+9tAgMBAAGjUzBRMB0GA1Ud
  DgQWBBRvOGSQcJs1EIu/p7rkpiBJcM0RTjAfBgNVHSMEGDAWgBRvOGSQcJs1EIu/
  p7rkpiBJcM0RTjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCH
  IyjCj977mqgPEpl7FAv3SaocZWB4btnjtLAkbc0HMmIVLU/alSDJom68ce1SEpFo
  5eDuz7LbI72lui7g4Iy0fe1KIqRDbdKek8rPuHRLjobAyFdAVUpUsH8UxDLil91P
  EIkw4v1qc8VukCz/2gxev+/IUx1UJLMCnKAW8sBRX9JQ/gqj6gC/NTeR58fDkX/E
  0eRwSg19pyZQi5zYFZORdEzLCJtzJa+hbSaEAA76znquR3ccj7dasIVuEBb+AGPn
  TzSuXnJOCyNfi2kHD1kL9/raWAjn7tvLcQahji1qGnoBYLa1XXgmzq8OKRhjk24N
  bHBRj4y/AaMs768fDutB
  -----END CERTIFICATE-----
  </ca>
  ```
* 嘗試連線，帳密請跟我註冊。
* 帳密可以直接給我又或是到我的電腦上打
* 連線後，連至 192.168.14.210:8006 進入 PVE
  帳號 : root
  密碼 : selab1623

### 創建 VM 注意事項 :

1. 點選右上方 Create VM
2. Name 可自訂，OS 目前有 Ubuntu 20.04 Server 以及 Desktop 版
3. System 初始即可，Qemu Agent 可以打勾(說是可以更節省 Memory?)
4. Disks 請使用 HDD 其中一個(每個 HDD 各 1 TB)，Size 看剩多少空間
5. CPU 目前是使用 i7-6700 (8 Core)，不要設定太多應該都行
6. Memory 可以看目前我們使用多少再決定
7. Network 初始即可，有 DHCP，192.168.14.XXX
8. 最後檢查設置是否正確，接著 Finish

### 連線至 VM

1. 左欄可以看到剛建的 VM，選擇它(selab 下)
2. 點選 Console 啟動 VNC 連線

::: success
目前缺點是無法複製貼上，建議可以用個 SSH 來連線！
記得先找我建立 OpenVPN 帳密，有任何問題再提出來！
:::


## 2023/12/27
* QEMU - 是個開源的 Machine emulator 跟 virtualizer.
* 若是要在 VM 中安裝 QEMU，需要啟動
  ![image](https://hackmd.io/_uploads/HJvINUYwT.png)
  但因為我的電腦是有開啟 HyperV(Windows 虛擬機器)，所以無法啟動此選項。

* Syzkaller 是 Kernel Fuzzer，可以模擬其他 OS 環境，並在其中 Fuzzing 驅動程式。

## 2023/12/20
目前已知的 Kernel Fuzzer : 
* [kAFL](https://github.com/IntelLabs/kAFL)
  * 需要 Intel Gen-6 的 CPU (for Intel PT)，Ubuntu LTS (>=20.04)
  * 並未在 ClusterFuzz 實作 Fuzzer
* [Syzkaller](https://github.com/google/syzkaller)
  * 以 Golang 1.20+ 撰寫，Google 開發，自行架設容易
  * ClusterFuzz 中有這個 Fuzzer

## 2023/12/11
* 嘗試用 kubeadm 架設 ClusterFuzz 在 k8s : 
  > [參考莊永的方式](https://hackmd.io/@s8952889/SkjgRZtXp#3-Installing-kubeadm-kubelet-and-kubectl)
:::  danger
  * 原先嘗試自己研究來架設，但最後把 VM 網路搞炸了...(可能是 VM Memory 滿了)
  * **建議照莊永的步驟走**，以及安裝 [k9s](https://github.com/derailed/k9s) 來看 pod 比較方便
:::
::: success
* 最後照著莊永的步驟走，成功架設 Cluster 在 k8s 中：
  * 所有 Pods
    ![image](https://hackmd.io/_uploads/rJrORF48T.png)
  * ClusterFuzz 的 Testcases page
    ![image](https://hackmd.io/_uploads/S1wqRFE8T.png)
  * 目前還無法從 VM 外進到 Page
:::
:::   info
* Install k9s on Ubuntu 20.04
  * [Choose your best installation method](https://github.com/derailed/k9s#installation) (這邊使用 snap)
    ```bash
    snap install k9s
    ln -s /snap/k9s/current/bin/k9s /snap/bin/
    ```
  * Try k9s
    ```
    k9s help
    # K9s is a CLI to view and manage your Kubernetes clusters.
    ```
:::

## 2023/12/06
:::  success
* 嘗試使用學弟架設的 docker hub：
  * 在 Windows 上，使用 Docker Desktop 的話 :
  * 按下 Win + R 並輸入 `%userprofile%` 打開資料夾
  * 在此目錄下打開 WSL，並輸入
    ```sh
    sh -c 'mkdir -p ./.docker/certs.d/140.124.183.93/ && openssl s_client -showcerts -connect 140.124.183.93:443 < /dev/null | sed -ne "/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p" > ./.docker/certs.d/140.124.183.93/ca.crt'
    ```
  * 重啟 Docker Desktop
  * 後面步驟參考[學弟的教學](https://hackmd.io/t1b2S2PcTiemo6iHYNTAKg#20231121-Harbor-%E5%BB%BA%E7%BD%AE%E5%8F%8A%E6%B8%AC%E8%A9%A6)
:::

## 2023/11/30 Meeting
* 嘗試使用 Fluentd 來收集所有 log

## 2023/11/30
* Local / Containerize 的差異：
  * 各自使用 1 bot 做 Fuzzing
  * 6 小時 (0900 觸發 load bigquery stats)
  * benchmark: projv4 with corpus
* Local :
  * Processor : 2
  * Memory : 8 GB
  * 1 VM Clusterfuzz, 1 VM bot
  ::: spoiler
    * ![image](https://hackmd.io/_uploads/ryhrLGJHT.png)
    * ![image](https://hackmd.io/_uploads/rJoSSGkBp.png)
    * ![image](https://hackmd.io/_uploads/rk1w8zJBp.png)
  :::
  * Test Case : 2
  * tests_executed : 39,643,636
  * Unique crashes : 4
* Containerize
  * CPU : 2
  * Memory : 8 GB
  ::: spoiler
    * ![image](https://hackmd.io/_uploads/Bkx4WsbHT.png)
    * ![image](https://hackmd.io/_uploads/BJ_HbjWHa.png)
    * ![image](https://hackmd.io/_uploads/ByR8bsZH6.png)
  :::
  * Test Case : 2
  * tests_executed : 51,090,857
  * Unique crashes : 3
* 在測試中，雖然在 Unique crashes 容器化版本只找到 3 個，但他的 test case 執行次數比 Local 版的還要多很多(相差 11,447,221)

## 2023/11/29
* 把 Bot log 收集一起，可以更容易檢查 Log，不須進到 Bot 的資料夾中
  * 目前使用 `cp -u` 的方式收集，並每秒執行一次，持續更新，Bot 關閉時也會再次更新一次。
  * 存至 local/storage/bot_log 中。

## 2023/11/23
* 測試時，不要讓其他應用程式一起跑，以免受到干擾(即使是在容器中)

## 2023/11/19
* Local / Containerize 的差異：
  * 各自使用 1 bot 做 Fuzzing
  * 24 小時
  * benchmark: projv4 with corpus
* Containerize
  * 2 cpu, 8 GB Memory
  ::: spoiler
  * ![image](https://hackmd.io/_uploads/SyNCOZ9VT.png)
  * ![image](https://hackmd.io/_uploads/HJQbKW946.png)
  * ![image](https://hackmd.io/_uploads/Hkr6Ob9Vp.png)
  :::

* 發現到的問題：容器化的版本與之前的實驗比較發現之前的每秒平均執行測試次數比較多，卻只使用較少資源(1 cpu, 4 GB Memory)，可能跟測試的 INPUT 有關係，導致 Fuzzing 陷入較長的測試執行時間！

* Local :
  * Processor : 2
  * Memory : 8 GB
  * 1 VM Clusterfuzz, 1 VM bot

## 2023/11/14
* Local / Containerize 的差異：
  * 各自使用 1 bot 做 Fuzzing
  * 24 小時
  * benchmark: projv4 with corpus
  * 檢查 tests_executed
* Containerize : 
  * 1 cpu, 4 GB Memory
  ::: spoiler
  * ![image](https://hackmd.io/_uploads/By5hHy0Xp.png)
  * ![image](https://hackmd.io/_uploads/SkGCHJC7p.png)
  * ![image](https://hackmd.io/_uploads/BJMQByCQa.png)
  :::
* Local :
  * Processor : 4
  * Memory : 8 GB
  ::: spoiler
  * ![image](https://hackmd.io/_uploads/B1-91LX46.png)
  * ![image](https://hackmd.io/_uploads/H1OjJIXEa.png)
  * ![image](https://hackmd.io/_uploads/HyaAJUXEa.png)
  :::
* 兩者比較下來，Local 測試執行次數較多，但因兩者 Bot 的配置不同，所以可能有差異！

  

## 2023/11/06
:::  success
新增 `--time-budget` 的參數，範例如下
```bash
python butler.py run_bot --name botName --time-budget 1 /my/bot/path
```

並新增一個環境變數 `BOT_TIME_BUDGET_HOURS` 讓 container 也能夠設定執行時間
```
...
      environment:
        BOT_TIME_BUDGET_HOURS: 3 # Run bot for 3 hours
...        
```
這樣在測試時就不需要記錄 bot 執行多久，並且也能夠 bot 自己停止 Fuzzing。
:::
  
## 2023/10/30
:::  success

對於檢查 bigquery emulator 是否正常運行，目前使用 `/health/{projectID}` 來測試
* 當以下項目都通過時，即 Bigquery Emulator 正常運作
  * 是否可以處理 Request
  * 是否可以做 Query (SELECT 1)
  * 是否可以建立 Job
  * 最後刪除建立的 Job
* 回傳 OK (200) 即為正常，若是回傳 Error Response (500)，即不正常，需重啟。

:::
## 2023/10/26 (Meeting)
* 嘗試在不同台機器(實體機)做 Fuzzing
    * NFS 與 Clusterfuzz service 在不同機器上運作。

## 2023/10/19
::: info
* 使用容器化的各個 service 做 Fuzzing : (Start : 2023/10/19 18.55)
    * services
        * cluserfuzz-server
        * datastore-emulator
        * pubsub-emulator
        * gcs-emulator
        * bigquery-emulator
        * cron-service
        * clusterfuzz-cron-server
        * bot * 4 (1 CPU, 1 GB Mem)
    * target
        * proj4
    * end time : 2023/10/22 14.45 ( 2 days 19 hours 55 mins )
    * result : 
        * ![](https://hackmd.io/_uploads/rk1d8SMfa.png)
        * ![](https://hackmd.io/_uploads/r1snISzMp.png)
        * 測試過程中，並無發現任何問題
:::

## 2023/10/08
:::success
目前已經對容器化的 Bot 做測試(run 4 days)，並且能夠獲取 Crash 並顯示在 Page 上，其中並未發生錯誤。
![](https://hackmd.io/_uploads/H1QD_4BZp.png)

:::

## 2023/10/04
:::  success
目前已經接近完成 bot 的 containerize 並且開了 [PR](https://github.com/ntutselab/clusterfuzz/pull/11)，但目前還有些問題：
* **權限問題**，此問題在 PR 中有提及。
* **擴展性問題**，目前因為直接把整個專案包進容器中，因此當我們修改程式碼或是設定時，需要再重新打包進容器才能運作。
* **網路問題**，因為目前我這邊只有把 Bot 容器化並測試，所以不清楚當其他 Services 容器化後連線會不會有問題。
:::

## 2023/09/26
:::  success
* 已成功在兩台 Bot VM 中跑 Fuzzing，並寫了一個 Script 簡化流程
  ![](https://hackmd.io/_uploads/BktZsJxxa.png)

:::

## 2023/09/25
:::success
已成功把 Samba 換成 NFS，整個 ClusterFuzz & Bot 安裝步驟如下 : 
* 安裝
  * 伺服端 (ClusterFuzz)
    ```bash
    sudo apt update
    sudo apt install nfs-kernel-server
    ```
    * 至 ClusterFuzz 資料夾下跑 `./local/install_deps_linux.bash`
  * 客戶端 (Bot)
    ```bash
    sudo apt update
    sudo apt install nfs-common
    ```
    * 至 ClusterFuzz 資料夾下跑 `./local/install_deps_linux.bash`
* 設置
  * 伺服端 (ClusterFuzz)
    * 對 `/etc/exports` 編輯 (`sudo nano /etc/exports`)，在最底部輸入 :
      ```
      <your cluster path>      *(rw,sync,no_subtree_check)
      ```
      * <your cluster path> : 指定的 NFS 共享資料夾
      * \* : 允許所有網路存取，可以是 IP
      * rw : 掛接的客戶端對共享資料夾的存取權限
      * sync : 同步寫入資料(即寫入資料伺服端以及客戶端兩者資料是同步的)
      * no_subtree_check : 不檢查共享資料夾的父資料夾權限
    * 對 ClusterFuzz 資料夾下的 `./local/emulators/gcs.go` 編輯
      * 把 600 改成 666
      ```go=278
      	return ioutil.WriteFile(fsPath, encoded, 0666)
      ```
      * 把 700 改成 777
      ```go=295
      	return os.MkdirAll(filepath.Dir(path), 0777)
      ```
      * 把 localhost 刪掉
      ```go=305
      	http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
      ```
    * 對 ClusterFuzz 資料夾下的 `./src/local/butler/constants.py` 編輯
      * 把 localhost 改成 0.0.0.0
      ```python=74
      DATASTORE_EMULATOR_HOST = '0.0.0.0:' + str(DATASTORE_EMULATOR_PORT)
      ```
      ```python=77
      PUBSUB_EMULATOR_HOST = '0.0.0.0:' + str(PUBSUB_EMULATOR_PORT)
      ```
      * 把 localhost 改成 VM IP
      ```python=80
      LOCAL_GCS_SERVER_HOST = 'http://<your vm ip>:' + str(LOCAL_GCS_SERVER_PORT)
      ```
  * 客戶端 (Bot)
    * 掛接 ClusterFuzz 資料夾，在 Terminal 輸入 : 
      ```bash
      mkdir <your mount dir>
      mount -t nfs -o nolock <server ip address>:<your cluster path(same with /etc/exports)> <your mount dir>
      ```
    * 對 ClusterFuzz 資料夾下的 `./src/local/butler/constants.py` 編輯
      * 把 localhost 改成 ClusterFuzz IP 
        ```python=74
        DATASTORE_EMULATOR_HOST = '<clusterfuzz ip>:' + str(DATASTORE_EMULATOR_PORT)
        ```
        ```python=77
        PUBSUB_EMULATOR_HOST = '<clusterfuzz ip>:' + str(PUBSUB_EMULATOR_PORT)
        ```
        ```python=77
        BIGQUERY_EMULATOR_HOST = 'http://<clusterfuzz ip>:' + str(BIGQUERY_EMULATOR_PORT)
        ```
  
* 運行 ClusterFuzz & Bot
  * 伺服端 (ClusterFuzz)
    * 在 ClusterFuzz 資料夾下進入虛擬環境後輸入 `python butler.py run_server --bootstrap`
  * 客戶端 (Bot)
    * 在 ClusterFuzz 資料夾下進入虛擬環境後輸入 `python butler.py run_bot --name <your bot name> --server-storage-path <your mount dir>/local/storage <your bot folder path>
`
:::

## 2023/09/21 (Meeting)
:::info
* Samba -> NFS
* Multi Bots
:::

## 2023/09/17
:::success
* 目前針對 Fuzz bot containerize 已可以在不同 VM 做 Fuzzing
* 使用 samba 分享 clusterfuzz folder，並在 Bot 使用 mount 方式做掛載
  * 在 ClusterFuzz 端設定 samba 權限並讓其分享 ClusterFuzz 的 Folder
  * 修改 local/emulator/gcs.go 的 L278 以及 L295 後面的數字，改成 777 (暫定)
  * 修改 datastore、PubSub 以及 bigquery emulator 的 HOST
    * ClusterFuzz 端修改成 0.0.0.0
    * Bot 端修改成 ClusterFuzz 端的 IP
  * 跑 Bot 時輸入(**使用 root 權限**)
    ```
    python butler.py run_bot --name <fuzz-bot-name> --server-storage-path <your-mount-path>/local/storage <fuzz-bot-folder>
    ```
  * 如果出現 Permission Denied 是 Bot 端沒有權限寫入資料，需要開啟 `local/storage` 底下所有權限 (chmod rwx)
:::

:::warning
* 目前權限只能暫時先手動設定，還不清楚設定權限的位置，以及需要更動哪些權限，還要進一步了解並測試(主要是 ClusterFuzz 端的 local/storage 下的 local_gcs，如果父目錄權限不 OK 則子目錄也會發生錯誤，切記路徑上所有權限需設定！)
:::

  

## 2023/09/14 (Meeting)

* Fuzz bot remote
* Clusterfuzz 容器化
* 臺大版本與我們的版本結果比較(Memory Usage, Performance Testing)
  * 10 benchmarks
  * 12 hours

## 2023/09/12
* 目前臺大的程式碼運行大約兩天多 (09/10 晚上至 09/12 早上)

## 2023/09/11
* 針對臺大的程式碼透過 docker compose 建立 ( Local ) : 
  * 修改程式碼
    1. 修改 docker compose (local/docker-compose.yml)
        ```docker
        version: "3.9"  # optional since v1.27.0
        services:
          server-1:
            ports:
              - 9051:9000  # 裡面的9000對到外面9051
              - 9008:9008  # 裡面的9008對到外面9008
            volumes:
              - ..:/workspace
            stdin_open: true
            tty: true
            working_dir: /workspace
            environment:
                LOCAL_METADATA_PORT: 9050 # 剛剛metadata server的port 
                LOCAL_METADATA_SERVER: 172.17.0.1
                TEST_BLOBS_BUCKET: clusterfuzz-ci-blobs
                TEST_BUCKET: clusterfuzz-ci-test
                TEST_CORPUS_BUCKET: clusterfuzz-ci-corpus
                TEST_QUARANTINE_BUCKET: clusterfuzz-ci-quarantine
                TEST_BACKUP_BUCKET: clusterfuzz-ci-backup
                TEST_COVERAGE_BUCKET: clusterfuzz-ci-coverage
                LOCAL_SRC: 1
            image: gcr.io/clusterfuzz-images/ci
            command: /bin/bash -c "./local/install_deps_linux.bash && tail -f /dev/null" # New added for init install

          mongodb: # New added for local mongoDB
            image: mongo
            restart: always
            ports:
              - 27017:27017
            environment:
              MONGO_INITDB_ROOT_USERNAME: root
              MONGO_INITDB_ROOT_PASSWORD: example

          drill: # New added for local apache drill
            image: apache/drill:1.19.0
            ports:
              - 8047:8047   # Web UI 
              - 31010:31010 # ODBC/JDBC
            stdin_open: true

          redis: # New added for local redis
            image: redis
            ports:
              - 6379:6379
            restart: always
        ```

    2. 修改 redis host (src/clusterfuzz/_internal/base/memoize.py)
         ```python=32
         ...
         _DEFAULT_REDIS_HOST = 'redis'
         ...
         ```
    3. 修改 apache drill host (src/clustefuzz/_internal/local_storage/apache_drill.py)
         ```python=12
         ...
          conn = jaydebeapi.connect(
            'org.apache.drill.jdbc.Driver',
            'jdbc:drill:drillbit=drill'
         )
         ...
       ```
    4. 修改 mongo host, port, account (src/clustefuzz/_internal/local_storage/mongo.py)
        ```python=1
        import pymongodb

        _DEFAULT_MONGODB_HOST = 'mongodb'
        _DEFAULT_MONGODB_PORT = 27017
        _DEFAULT_MONGODB_USERNAME = 'root'
        _DEFAULT_MONGODB_PASSWORD = 'example'

        def insert_rows(db, col, rows):
            myclient = pymongo.MongoClient(
                host=_DEFAULT_MONGODB_HOST, port=_DEFAULT_MONGODB_PORT,
                username=_DEFAULT_MONGODB_USERNAME,password=_DEFAULT_MONGODB_PASSWORD)
        ...
        ```
        ```python=24
        def reset():
            myclient = pymongo.MongoClient(
                host=_DEFAULT_MONGODB_HOST, port=_DEFAULT_MONGODB_PORT,
                username=_DEFAULT_MONGODB_USERNAME,password=_DEFAULT_MONGODB_PASSWORD)
        ...
        ```
    5. 修改 GCS host (src/local/butler/constant.py)
        ```python=77
        ...
        LOCAL_GCS_SERVER_HOST = 'http://127.0.0.1:' + str(LOCAL_GCS_SERVER_PORT)
        ...
        ```
  * Install
    1. 確保有安裝 docker compose，並到 docker-compose.yml (local/docker-compose.yml) 輸入 : 
     ```cmd
     docker compose up -d
     ```
    2. 查看 container log 等 install 結束，只要出現 `Installation succeeded!` 代表安裝成功！
    3. 開 container CLI，打開 cmd 並輸入 `docker exec -it <container id> /bin/bash`
    4. 之後進入虛擬環境輸入 `python3 -m pipenv shell`
    5. 初始化 server 輸入 `python butler.py run_server --bootstrap`
    6. 完成後 `ctrl + c` 後並輸入 `pipenv install pandas pymongo jaydebeapi jpype1` 安裝 Module
  * 啟動 clusterfuzz 輸入 `python butler.py run_server --skip-install-deps`
  * Apache drill
      * 目前 apache drill 要連接 mongo 需要進 drill 的 Web UI (http://localhost:8047) 並至 Storage 中找出 Mongo 並 `Enable`。
      * 設定 Mongo Update，在 Configuration 輸入 (需修改 connection 的部分): 
        ```
        {
          "type": "mongo",
          "connection": "mongodb://root:example@172.27.0.1:27017/",
          "enabled": true
        }
        ```
        修改後並按 `Update`
      * 至 Options 的地方(右上方)，搜尋 `mongo`，並調整 `store.mongo.all_text_mode`，Value 調成 False (如果原本是 False 的話可以先改成 True，Update，再改成 False)。
      * 測試看看，至左上 Query，輸入 `show databases;` 如果有出現結果代表成功連結。
## 2023/09/06
:::info
* 為了測試在不同 VM 上是否可以跑 clusterfuzz 以及 Bigquery-Emulator，所以在兩台 VM 分別跑 bigquery-emulator 以及 clusterfuzz & bot。
  * 開始時間：09/06 20:05
    * Fuzz Target : sqlite-2016-11-14-fsanitize_fuzzer_build (without corpus)
    * VM env(ClusterFuzz & bot) : 
      * 4 processor
      * 16 GB RAM
      * using [ntutselab/clusterfuzz](https://github.com/ntutselab/clusterfuzz) master branch
    * VM env(bigquery-emulator) : 
      * 2 processor
      * 4 GB RAM
      * using [ntutselab/bigquery-emulator](https://github.com/ntutselab/bigquery-emulator) master branch
  * 中途紀錄時間 : 09/07 10:45 (after 12 hs 40 mins)
    * 目前 Fuzz target (sqlite) 還未找到 crash，所以 Crash Stat 以及 Test Case 無資料，只有 Fuzzer Stat 有而已
    ![](https://hackmd.io/_uploads/BkLct3IA3.png)
    * 從目前狀況來看 bigquery-emulator 可以在與 clusterfuzz 不同 VM 下執行，並且功能與在相同 VM 下執行相同。
:::

## 2023/09/03
:::info
* 透過論文以及原始碼可以知道：
  * 其 ClusterFuzz 使用 [Apache drill](https://drill.apache.org/) 作為查詢引擎，[MongoDB](https://www.mongodb.com/en-us) 作為其後台資料庫。
    * 使用 jaydebeapi 以 JDBC 與 apache drill 連線
  * 把 Bigquery SQL 換成 Apache drill 使用的 SQL。而如果某些換不了的情況下，會以其他方式做處理。
  
    ![](https://hackmd.io/_uploads/H1UkZKl0n.png)
    
    圖中步驟顯示 SQL Statement 中的流程，groupByField 以及 FinalResult 中有使用到 `ARRAY_AGG(STRUCT())`，而因為需要的結構陣列 Apache drill 無法產生。所以在這兩個步驟上 : 
    * 先把數據轉成 pandas 的 dataframe 再對其屬性進行分組
    * 再對分組後的資料進行聚合操作,並將目標屬性存為與原始結果相同的結構陣列
  * 在 Apache drill 無法讀取一筆資料中，具有陣列的格式(e.g. JobRun 的 crashes)，解法是把陣列型態的資料轉成一筆一筆的資料存入。在讀取時也是改成一筆一筆讀取。

* **功能**上與我們的版本應該是差不多的，可上傳 Job 並運行 Bot 跑 Fuzzing，最後也能夠看到 Crash Statistic 以及 Fuzzer Statistic 的結果，論文中也說與 Cloud 版的 ClusterFuzz 結果相似。

* **效能**上與我們的版本可能就有差別，因為我們使用的是 Bigquery Emulator，其背後是以 sqlite 作為資料庫，而臺大版本則是 Apache drill 與 MongoDB，兩者相比效能應該是臺大那邊的會更好(不過沒有做過測試，這只是從工具上來比較)。

* **模擬服務**上與我們的版本有些差別，因為我們是去模擬 Google Cloud 的服務，所以很多原有的 API 都還是能夠使用的，但臺大版本是為了達到功能相同而修改的，這樣就必須把所有使用到 API 的部分改成本地化！而目前從程式碼來看，臺大版本只修改有達到 Crash Statistic 以及 Fuzzer Statistic 的相關程式碼，其餘並未做本地化(比如 `regression page` 的 `src/appengine/handlers/commit_range.py`)。如果未來要擴大功能，關於 big_query API 的功能就無法使用。

:::

## 2023/08/31 Meeting
* 先把台大的 code Run 看看

## 2023/08/31
:::info
* 目前正往 clusterfuzz 的 bot 能夠異端(非本地端)開啟並能使用：
  * 嘗試 clusterfuzz 中 [build_on_container_builder.sh](https://github.com/google/clusterfuzz/blob/v2.6.0/docker/build_on_container_builder.sh) 是否能夠拿來使用
  * 又或是依照 [README.md](https://github.com/google/clusterfuzz/blob/v2.6.0/local/README.md#running-a-bot-locally) 中R unning a bot locally 的方式
  * 研究在 [butler.py](https://github.com/google/clusterfuzz/blob/v2.6.0/butler.py) 中 `_setup_args_for_remote`
:::

## 2023/08/10
:::info
* `08/10 09:05 - 08-10 15:05`、`08/10 15:25 - 08/10 21:25`、`08/10 21:15 - 08/11 09:15`
  * 硬體配置：
    開 4 台 bot （ 4 core, 16G Ram），使用雲端 With_corpus 的 10 個 target
    * Job name: libfuzzer_asan_{target_name}
    * template: libfuzzer, engine_asan, prune
  * 測試設置：
    *  前6小時,第一組：lcms, proj4, json, openssl, c-ares
    *  接著關掉4個bot, 刪掉這5個jobs, 接著
    *  後6小時,第二組：re2, vorbis, sqlite, openthread-radio, openthread-ip6
    *  接著關掉4個bot, 讓run_server開著掛機掛到早上9點讓他觸發load-bigquery-stats, 確認fuzzer_stats crash_stats圖表有東西
  *  First stage
    *  ![](https://hackmd.io/_uploads/HyZCAbf32.png)
    *  ![](https://hackmd.io/_uploads/Bycm1GGh2.png)
    *  ![](https://hackmd.io/_uploads/B1iZkGM23.png)
    * test-bigquery-bucket :
      * JobRun : 22 files
      * TestCaseRun : 49 files
    * test-fuzz-logs-bucket :
      * log : 49 files
      * testcase : 40 files
  * Second stage(不小心睡著了多跑兩個小時 08/10 15:25 - 08/10 23:40 共 8 小時 15 分鐘)
    * ![](https://hackmd.io/_uploads/SJJOrYMhh.png)
    * ![](https://hackmd.io/_uploads/ry1YHKM3n.png)
    * [Crash Stats Page 1](https://drive.google.com/file/d/1h47DF4YkqpFXXdiWveA61K2hE0w-f3d8/view)
    * [Crash Stats Page 2](https://drive.google.com/file/d/19x6bfPY5Jedh0PKNZG7OoAgfT7zd98J9/view)
    * test-bigquery-bucket :
      * JobRun : 37 files
      * TestCaseRun : 79 files
    * test-fuzz-logs-bucket :
      * log : 54 files
      * testcase : 79 files
  * Third stage
    * ![](https://hackmd.io/_uploads/ByTgKG7n2.png)
    * ![](https://hackmd.io/_uploads/H1sGKMmn2.png)
    * ![](https://hackmd.io/_uploads/BJfVKzm23.png)
    * [Fuzzer Stats (by Time)](https://drive.google.com/file/d/1cOX9KXAP0EX-v3IoEcTEx08ApStN_S-b/view?usp=sharing)
:::

## 2023/08/03
:::info
* 08/03 19:10 - 08/04 01:10 總計 6 小時：
  * Environment
    * localized without corpus
    * Fuzz Target : re2, vorbis, sqlite, openthread-radio, openthread-ip6
    * 4 bot
  * Results
    * Memory usage
      ![](https://hackmd.io/_uploads/BJWOJvKi2.png)
    * 這六個小時，bot 並沒有找到 Crash，所以 Crash Stat 是空的，且因為 `load-bigquery-stats` 並未被觸發，所以 Fuzzer Stat 也是空的
      ![](https://hackmd.io/_uploads/BJl8-wYih.png)
    * test-bigquery-bucket :
      * JobRun : 4 files
      * TestCaseRun : 12 files
    * test-fuzz-logs-bucket :
      * log : 12 files
      * testcase : 0 files
:::

## 2023/08/01
:::info
* 目前由莊永確認，應該是 `bigquery-emulator` 的 `go-zetasql` 中用到許多 pointer，但用完並沒有釋放！
  [go-zetasql/parse_resume_location.go](https://github.com/goccy/go-zetasql/blob/main/parse_resume_location.go)
  ```go
  // NewParseResumeLocation creates ParseResumeLocation instance.
  func NewParseResumeLocation(src string) *ParseResumeLocation {
      var v unsafe.Pointer
      internal.ParseResumeLocation_FromStringView(unsafe.Pointer(C.CString(src)), &v)
      return &ParseResumeLocation{raw: v}
  }
  ```
  > https://github.com/ntutselab/bigquery-emulator/issues/8#issuecomment-1656138856

* 使用 GC trace 發現每次 insert 大筆資料後，使用的 Memory 會從 26 MB 左右被 GC 清掉 5 至 10 MB，並沒有完全清除，日積月累後，Memory 一定會 OOM！

* 嘗試使用 `debug.FreeOSMemory()` 釋放**但無效**，這個 function 是可以強制進行 GC，但目前認為無效的原因是因為這個 pointer 是被標記還在使用的，導致無法消除。
* 嘗試 rerun 整個 program，因為 main() 只呼叫 run() 這個 method，所以嘗試把整個 server 透過 API 關閉後再執行 run()，具體作法如下，**但結果還是無法讓 Memory 釋放**！
  ```go
  func main() {
      fmt.Sprintf("Close Server %d ...", int(run()))
      os.Exit(int(run()))
  }
  ```
  
* 最後透過建立 Proxy Server(Flask) 讓 `bigquery-emulator` 作為其子進程，透過 API 開啟以及關閉，具體作法如下：
  * `/open` : 開啟 `bigquery-emulator`，回傳 `Emulator started`。若已開啟，則回傳 `Emulator is already running`
  * `/close` : 關閉 `bigquery-emulator`，回傳 `Emulator stopped`。若已關閉，則會傳 `Emulator is not running`
  
  測試以這樣的方式，**可以讓 `bigquery-emulator` 的 Memory 釋放**，並且因為[莊永PR](https://github.com/ntutselab/bigquery-emulator/pull/7)讓 `bigquery-emulator` 可以重啟且不遺失資料，讓這樣的操作可行！
  
  之後還會增加一些功能，可以透過 API 的方式得知 `bigquery-emulator` 的狀況，但目前還在討論中。
:::

## 2023/07/20
:::info
* 目前使用 golang 內建的 `pprof` 工具來分析內存問題，能夠更直觀地看到程式中的使用狀況：
  ![](https://hackmd.io/_uploads/H1eaYrL9n.png)
  
  ![](https://hackmd.io/_uploads/S1uWVQUqh.png)
  
  ![](https://hackmd.io/_uploads/r1xNBQ8c3.png)
  
  * Flat：函數分配的內存，不包含它調用其他函數造成的內存分配。
  * Flat%：Flat / Total
  * Sum%：自己和前面所有的 Flat% 累積值
  * Cum：這個函數分配的內存，以及它調用其他函數分配的內存之和。可以解讀為因為這個函數所造成的所有內存分配。
  * Cum%：Cum / Total

  可以直接用網頁查看(僅限本地) : [連結](http://192.168.245.141:8000/ui/top?si=alloc_space)

:::

## 2023/07/18
:::info
* 使用莊永修改過的 Emulator (能顯示 Memory 使用量)，以及楷融學長寫的能造成 OOM 的程式碼。
* 使用`56 分 18 秒`後就造成 Emulator Out Of Memory
  ![](https://hackmd.io/_uploads/HkuN2YXqh.png)
  
  ![](https://hackmd.io/_uploads/By852YXc2.png)

:::

## 2023/07/10
:::info
* 測試因為內核問題而中斷 (查看 `/var/log/syslog` 得到的結果)：
  ![](https://hackmd.io/_uploads/H16I-mFYn.png)
  無法肯定是不是 Fuzzing 導致的！(相關 Log 沒出現錯誤)
* 因上述原因導致 VM 意外重啟，以下為效能結果：
  * 1 Month
    ![](https://hackmd.io/_uploads/rJ5eG7tFn.png)
  * 1 Week
    ![](https://hackmd.io/_uploads/H1IDf7tYn.png)

  其中 Memory 在 07 Jul 後就開始平穩，原因是因為 Bot 不明原因停止，出現：
  ![](https://hackmd.io/_uploads/r1P047KFh.png)
* 而且當沒新增任何 Crash 時，Memory 占用還是很高
:::

## 2023/07/06
:::info
* 新測試結果：
  ![](https://hackmd.io/_uploads/rJMlHb4Fh.png)
* 正常使用下(含 Corpus)，Memory 會持續上升，目前還沒OOM，但可以預測會OOM!
:::
 
## 2023/07/03
:::info
目前測試從`2023-06-29 13:09:51`至`2023/07/03 13:16:22`(運行 126 小時 31 分鐘，持續運作中)
* 實驗設置：
  * Fuzz Target : proj4 並附上 Corpus
  * Bigquery Emulator 使用修改過的版本( jobs.query() 可以產生 job 的版本 )
  * Cron Service 使用修改成按照 UTC 作為時間的版本
  * ClusterFuzz(Localize version 2.6.0)
  * 前置步驟與之前相同
* 目前結果：
  * Crash Statistics : 目前使用正常，且因為有使用 Corpus，所以 Crash 很多，較容易觸發 Crash。
    ![](https://hackmd.io/_uploads/H1jSE1xtn.png)
  * Fuzzer Statistics : 目前使用正常，且因為使用 UTC 作為 Cron Service 時間，所以能在正確的時間觸發 load-bigquery-stats，
    ![](https://hackmd.io/_uploads/rk18r1xF2.png)
    而圖表能夠顯示！
  * 在 DB 的部分並沒有產生任何 destination tables，符合預期
    * libfuzzer.JobRun : 3293 rows
    * libfuzzer.TestcaseRun : 6590 rows
    * main.crashes : 6990 rows
    * main.crash_stats : 377 rows
  * test-bigquery-bucket : 
    * JobRun : 3493 files
    * TestCaseRun : 6991 files
  * test-fuzz-logs-bucket : 
    * log : 6991 files
    * testcase : 6991 files
  * Monitorix : 從 06/29 13:16 開始，所以從 29 Jun 與 30 Jun 中間開始 
    ![](https://hackmd.io/_uploads/r14ltyxF2.png)
    
    ![](https://hackmd.io/_uploads/SJR8t1xF2.png)


* 測試中的小插曲：
  * 在 2023-06-30 00:17:44 發生不明原因 2103295 WORKER TIMEOUT
    ![](https://hackmd.io/_uploads/SyJhd1xYn.png)
    之後重新 booting 後就沒 WORKER TIMEOUT 這個問題了！ (目前看來不是 Memory 的問題)
    
  * BOT 發生 Exception (目前不確定 Exception 發生時間，所以無法肯定與 WORKER TIMEOUT 是否有關！)
    ![](https://hackmd.io/_uploads/H1bE5yet3.png)
    雖然發生 Exception，但還是能夠正常運作，所以這部分應該可以無視！



:::

## 2023/06/28
:::  info
因為忘了改成 `jobs.query()` 的方式，所以整個重新測試，目前：
* 使用 `Monitorix` 作為記錄 Performance 的工具
* 使用 `proj4` 作為 Fuzz Target 並附上 Corpus
* 使用的 Cron Service 已修改成按照 UTC 作為時間
* 使用修改後的 `Bigquery-Emulator` ( jobs.query() 可以產生 job 的版本 )
* Setup 與之前相同
:::

## 2023/06/15
:::success
這次測試從 2023/06/02 00:13:40 至 2023/06/15 04:58:53，已測試 316 小時 45 分 13 秒(約 13 天)：
* **測試前置步驟：**
  * **Project** : 
    * Clone ClusterFuzz(Localize version 2.6.0)
    * Cron Service(從 ClusterFuzz 分離出來)
    * Bigquery-Emulator(3.1.0)
  * **Fuzz Target** (共 6 個): 
    * vorbis-2017-12-11-fsanitize_fuzzer
    * c-ares-CVE-2016-5180-fsanitize_fuzzer
    * proj4-2017-08-14-fsanitize_fuzzer
    * re2-2014-12-09-fsanitize_fuzzer
    * sqlite-2016-11-14-fsanitize_fuzzer
  * **Build Step**
    * 開啟 Bigquery-Emulator
    * 開啟 ClusterFuzz 把 `run_server.py` 中的 `start_cron_thread` 註解(只跑 Cron Service)，並把 `cron_server` 輸出(以[這樣](https://hackmd.io/rKOq7yyPTuKufRj2b0xwtw#20230601)的方式顯示)
    * 開啟 Cron Service (非 VM)
    * 把六個 Fuzz Target 用 Job 上傳至 ClusterFuzz 中
    * 開啟兩個 Bot
* ** 測試結果：**
  * Crash Statistics, Fuzzer Statistics 都正常顯示
  * Cron Service 的 request 都正常回應，沒有錯誤產生
  * Database：
    * libfuzzer_stats.JobRun: 262 筆
    * libfuzzer_stats.TestcaseRun: 526 筆
    * main.crashes: 322 筆
    * main.crash_stats: 147 筆
    * destination table: 39 個
  * Bucket :
    * test-bigquery-bucket: 
      * JobRun: 285 個檔案
      * TestcaseRun: 571 個檔案
    * test-fuzz-logs-bucket: 
      * 905 個檔案 (571 個 log、334 個 testcase、)
* 測試終止原因：電腦突然自動關機，導致測試被迫中止！
* 目前在 Test Case 以及 Crash Statistics 中只看到四個 Fuzz Target 有 Crash 以及 Test Case，分別為：
  * `c-ares-CVE-2016-5180-fsanitize_fuzzer`
  * `proj4-2017-08-14-fsanitize_fuzzer`
  * `re2-2014-12-09-fsanitize_fuzzer`
  * `vorbis-2017-12-11-fsanitize_fuzzer`
  
  剩下的`sqlite-2016-11-14-fsanitize_fuzzer`可能是因為時間關係，沒找到 Crash！

:::

## 2023/06/01
:::info
* 要查看 cron_server 的 log，可以在 command 中加入 ‵--config <conf 路徑>‵，修改如下：( src/local/butler/run_server.py )
  ```python=213
  ...
    cron_server = common.execute_async(
        'gunicorn -b :{port} main:app --config ./gunicorn.conf'.format(port=constants.CRON_SERVICE_PORT),
        cwd=os.path.join('src', 'appengine'))

    common.execute(
        'gunicorn -b :{port} main:app'.format(
            port=constants.DEV_APPSERVER_PORT),
        cwd=os.path.join('src', 'appengine'))
  ...
  ```
  之後在 `src/appengine/` 下建立 `gunicorn.conf` 並寫上 : 
  ```
  workers = 1
  accesslog = "<ACCESS 路徑>"
  errorlog = "<LOG 路徑>"
  timeout = 600
  loglevel = "debug"
  capture_output = True
  ```
  最後再開個 Terminal 使用 `tail -f <LOG 路徑>` 可以觀察 cron_server 輸出。
  
:::

## 2023/05/29

![](https://hackmd.io/_uploads/Hy_F9AbIh.png)
![](https://hackmd.io/_uploads/BJ4ysCbU2.png)

:::info
測試區間：2023/05/26 18:11:34 - 2023/05/29 14:47:22 (時長 68小時 35分鐘 48秒)
* 環境跟步驟與[下方相同](#20230523)
* 有把 run_server 中的 start_cron_thread 註解，讓 run_server 不會開 Thread
* 測試 CRON 結果：
  * cleanup 回傳 OK
  * build-crash-stats 回傳 OK (功能正常)
  * load-bigquery-stats 回傳 500 Intetnal Server Error
  * schedule-corpus-pruning 回傳 OK
  * schedule-progression-tasks 回傳 OK
  * triage 回傳 OK
* 在 2023/05/28 14:28:59 關閉 bot 後，檢查 Test Case 頁面居然是空的...
* Crash Statistics 結果與[下方相同](#20230523)
* `cron_server`並沒有因不明原因關閉，到測試結束後還是能夠正常工作！(需要多試幾次看能不能重現錯誤)
* load-bigquery-stats 在測試中總共被呼叫三次，這三次都回傳 500，錯誤如下：
  ```
  Bad configuration at: config (user@localhost)
  Traceback (most recent call last):
    File "/home/kyl/Desktop/ntutselab/clusterfuzz/src/appengine/handlers/base_handler.py", line 277, in dispatch_request
      return super(Handler, self).dispatch_request(*args, **kwargs)
    File "/home/kyl/Desktop/ntutselab/clusterfuzz/src/appengine/third_party/flask/views.py", line 163, in dispatch_request
      return meth(*args, **kwargs)
    File "/home/kyl/Desktop/ntutselab/clusterfuzz/src/appengine/libs/handler.py", line 99, in wrapper
      result = func(self)
    File "/home/kyl/Desktop/ntutselab/clusterfuzz/src/appengine/handlers/cron/load_bigquery_stats.py", line 247, in get
      if not big_query.get_bucket():
    File "/home/kyl/Desktop/ntutselab/clusterfuzz/src/appengine/clusterfuzz/_internal/google_cloud_utils/big_query.py", line 68, in get_bucket
      return local_config.ProjectConfig().get('bigquery.bucket')
    File "/home/kyl/Desktop/ntutselab/clusterfuzz/src/appengine/clusterfuzz/_internal/config/local_config.py", line 198, in __init__
      super(ProjectConfig, self).__init__(PROJECT_PATH)
    File "/home/kyl/Desktop/ntutselab/clusterfuzz/src/appengine/clusterfuzz/_internal/config/local_config.py", line 147, in __init__
      raise errors.BadConfigError(self._config_dir)
  clusterfuzz._internal.base.errors.BadConfigError: Bad configuration at: config
  ```
* 測試結束後因為 load-bigquery-stats 一直回傳 500 (在 9009 port 下)，所以嘗試使用 9000 port 發 load-bigquery-stats，結果功能是<font color="#00CF00">正常</font>的，libfuzzer_stats_JobRun 是有被 insert 資料進去的！
:::

## 2023/05/26
:::info
測試區間：2023/05/25 20:14:50 - 2023/05/26 13:53:16 (時長 17小時 38分鐘 26秒)
* 環境跟步驟與[下方相同](#20230523)
* 有把 run_server 中的 start_cron_thread 註解，讓 run_server 不會開 Thread
* 測試 CRON 結果：
  * cleanup 回傳 OK
  * build-crash-stats 回傳 OK (功能正常)
  * load-bigquery-stats 回傳 OK
  * schedule-corpus-pruning 回傳 OK
  * schedule-progression-tasks 回傳 OK
  * triage 回傳 OK 
* Crash Statistics 結果與[下方相同](#20230523)
* 在這次測試中，`cron_server`並沒有因為不明原因關閉，所以現在能確定，`cron_server`的問題並不是每次都會發生(又或是因為把 cron_thread 去掉)，需要再次進行更多次的測試
* load-bigquery-stats 雖然回傳 OK，但是 libFuzzer_stats.JobRun 並未產生資料，猜測是在上午一點(load-bigquery-stats 傳送的時間)並未產生資料，導致 Fuzzer Statistics 沒有資料生成。
* 最後使用 postman 傳送 load-bigquery-stats，來產生資料至 libFuzzer_stats.JobRun，但是在 Fuzzer Statistics 篩選後按 Submit，結果新出現的錯誤
  * `server/handler.go:2131  internalError   {"error" : "internalError: failed to sync catalog: failed to create catalog tables: failed to create catalog table: context canceled"}`
  
  因此 Bigquery Emulator 就再也無法作用，對 Bigquery Emulator 發 request 回應 `sql: connection is already closed`，猜測是 Emulator 已經與 sqlite 因為上述原因斷開連線。
:::

## 2023/05/23
:::info
以下為使用[莊永修正後的版本](https://hackmd.io/Sx7JXaQYS82DtYrWCiwBrQ#2023521-Self)測試結果：(05/22 17:21:53 - 05/23 16:12:50，時長 22小時 50分鐘 57秒)
* 環境：
  * Ubuntu 20.04.6 LTS
  * Processors: 4
  * Memory: 16 GB
  * ClusterFuzz version 2.6.0 ( Localized )
  * Bigquery Emulator 3.1.0
  * Cron service (獨立出來的)
  * Fuzz target: proj4 libfuzzer asan
* 測試的 cron：
  * cleanup
  * build-crash-stats
  * load-bigquery-stats
  * schedule-corpus-pruning
  * triage
* 測試啟動步驟：
  * 啟動 Bigquery Emulator
  * 啟動 ClusterFuzz 加上 `--bootstrap` 參數
  * 上傳 Fuzz target (proj4, libfuzzer, asan) 並把 job 分派給 libfuzzer
  * 啟動 Cron service 並記錄 request / response (獨立出來的 cron service)
  * 啟動 bot，並記錄 bot log
  * 等待測試結果...
* 測試結果：
  * Cron :
    * cleanup 回傳 OK
    * build-crash-stats 回傳 OK
    * load-bigquery-stats 在測試中因為 cron 故障導致無法確定功能是否正常
    * schedule-corpus-pruning 回傳 OK
    * triage 回傳 OK
  * Test Case : 
    * ![](https://hackmd.io/_uploads/BJeuZ3jHn.png)
  * Fuzzer Statistics :
    * 要測試時 emulator 有 crash 過，重啟後測試頁面是空的...
    * ![](https://hackmd.io/_uploads/Sk9Av2orn.png)
  * Crash Statistics : 
    * ![](https://hackmd.io/_uploads/BJmmfhjS3.png)

* build-crash-stats 可以正常使用，並確實有輸入資料至 Bigquery mulator
![](https://hackmd.io/_uploads/B1zhqpFr3.png)
![](https://hackmd.io/_uploads/SJRT9aFSn.png)

* 測試過程中，啟動 cron service 傳送 cron 兩個半小時後發現`time out`，目前不清楚原因，
  * 繼續跑了 18 個小時或是使用 postman 發結果還是一樣
  * 網頁還是能夠正常瀏覽，就是 9009 壞了！

* 測試結束後，在 Fuzzer Statistics 選 libfuzzer 接著選 proj4 的 job 按下 Submit，結果報錯導致 Bigquery Emulator 直接 crash！(可能是因為忘記測 Fuzzer Statistics，所以隔了一天才嘗試看其結果，導致出問題！我有把 VM 的狀態暫停過，不確定是不是這樣的原因...)
:::

以下為 Emulator 錯誤訊息
:::spoiler
```
unexpected fault address 0x0
fatal error: fault
[signal SIGSEGV: segmentation violation code=0x80 addr=0x0 pc=0xe224f9]

goroutine 910020 [running]:
runtime.throw({0x2fded39, 0xc000e0ddf0})
	:1198 +0x71 fp=0xc0002bc048 sp=0xc0002bc018 pc=0x43e231
runtime.sigpanic()
	:742 +0x2e5 fp=0xc0002bc098 sp=0xc0002bc048 pc=0x4539a5
github.com/goccy/go-zetasql/ast.Walk({0x18f5e00, 0x3}, 0xc0002bc338)
	:10 +0x79 fp=0xc0002bc0c8 sp=0xc0002bc098 pc=0xe224f9
github.com/goccy/go-zetasql/ast.Walk({0x32c30b8, 0xc000e0de00}, 0xc0002bc338)
	:12 +0x9f fp=0xc0002bc0f8 sp=0xc0002bc0c8 pc=0xe2251f
github.com/goccy/go-zetasql/ast.Walk({0x32cb360, 0xc000e0dde0}, 0xc0002bc338)
	:12 +0x9f fp=0xc0002bc128 sp=0xc0002bc0f8 pc=0xe2251f
github.com/goccy/go-zetasql/ast.Walk({0x32cb488, 0xc000e0dd40}, 0xc0002bc338)
	:12 +0x9f fp=0xc0002bc158 sp=0xc0002bc128 pc=0xe2251f
github.com/goccy/go-zetasql/ast.Walk({0x32cb5b0, 0xc000e0dd20}, 0xc0002bc338)
	:12 +0x9f fp=0xc0002bc188 sp=0xc0002bc158 pc=0xe2251f
github.com/goccy/go-zetasql/ast.Walk({0x32c97a0, 0xc000e0dd00}, 0xc0002bc338)
	:12 +0x9f fp=0xc0002bc1b8 sp=0xc0002bc188 pc=0xe2251f
github.com/goccy/go-zetasql/ast.Walk({0x32d0328, 0xc000e0dcc0}, 0xc0002bc338)
	:12 +0x9f fp=0xc0002bc1e8 sp=0xc0002bc1b8 pc=0xe2251f
github.com/goccy/go-zetasql/ast.Walk({0x32d0450, 0xc000e0d380}, 0xc0002bc338)
	:12 +0x9f fp=0xc0002bc218 sp=0xc0002bc1e8 pc=0xe2251f
github.com/goccy/go-zetasql/ast.Walk({0x32c97a0, 0xc000e0d368}, 0xc0002bc338)
	:12 +0x9f fp=0xc0002bc248 sp=0xc0002bc218 pc=0xe2251f
github.com/goccy/go-zetasql/ast.Walk({0x32d0328, 0xc000e0d328}, 0xc0002bc338)
	:12 +0x9f fp=0xc0002bc278 sp=0xc0002bc248 pc=0xe2251f
github.com/goccy/go-zetasql/ast.Walk({0x32d0450, 0xc000e0d310}, 0xc0002bc338)
	:12 +0x9f fp=0xc0002bc2a8 sp=0xc0002bc278 pc=0xe2251f
github.com/goccy/go-zetasql/ast.Walk({0x32c97a0, 0xc000e0d2f8}, 0xc0002bc338)
	:12 +0x9f fp=0xc0002bc2d8 sp=0xc0002bc2a8 pc=0xe2251f
github.com/goccy/go-zetasql/ast.Walk({0x32c98c8, 0xc000e0d2d0}, 0xc0002bc338)
	:12 +0x9f fp=0xc0002bc308 sp=0xc0002bc2d8 pc=0xe2251f
github.com/goccy/go-zetasqlite/internal.(*Analyzer).getParameterMode(0x203000, {0x7f30ec4a4af8, 0xc000e0d2d0})
	/home/kyl/go/pkg/mod/github.com/goccy/go-zetasqlite@v0.14.1/internal/analyzer.go:142 +0x71 fp=0xc0002bc360 sp=0xc0002bc308 pc=0x14da651
github.com/goccy/go-zetasqlite/internal.(*Analyzer).Analyze.func1()
	/home/kyl/go/pkg/mod/github.com/goccy/go-zetasqlite@v0.14.1/internal/analyzer.go:181 +0x7c fp=0xc0002bc428 sp=0xc0002bc360 pc=0x14dadfc
github.com/goccy/go-zetasqlite.(*ZetaSQLiteConn).QueryContext(0xc00000e870, {0x3278918, 0xc000fb79b0}, {0xc0009c100a, 0xa5a}, {0x509bf90, 0x0, 0x0})
	/home/kyl/go/pkg/mod/github.com/goccy/go-zetasqlite@v0.14.1/driver.go:194 +0x25a fp=0xc0002bc530 sp=0xc0002bc428 pc=0x157d29a
database/sql.ctxDriverQuery({0x3278918, 0xc000fb79b0}, {0x7f30ec4a4ad8, 0xc00000e870}, {0x0, 0x0}, {0xc0009c100a, 0xc0002bc610}, {0x509bf90, 0x0, ...})
	:48 +0x17d fp=0xc0002bc598 sp=0xc0002bc530 pc=0x6d3a3d
database/sql.(*DB).queryDC.func1()
	:1722 +0x175 fp=0xc0002bc660 sp=0xc0002bc598 pc=0x6dc0d5
database/sql.withLock({0x3236178, 0xc00022e2d0}, 0xc0002bc7b0)
	:3396 +0x8c fp=0xc0002bc6a0 sp=0xc0002bc660 pc=0x6e400c
database/sql.(*DB).queryDC(0xc000100000, {0x3278918, 0xc000fb79b0}, {0x3278870, 0xc001390f00}, 0xc00022e2d0, 0xc000089350, {0xc0009c100a, 0xa5a}, {0x509bf90, ...})
	:1717 +0x211 fp=0xc0002bc840 sp=0xc0002bc6a0 pc=0x6db9d1
database/sql.(*Tx).QueryContext(0xc00075bc00, {0x3278918, 0xc000fb79b0}, {0xc0009c100a, 0xa5a}, {0x509bf90, 0x0, 0x0})
	:2469 +0xcf fp=0xc0002bc8b0 sp=0xc0002bc840 pc=0x6df1af
github.com/goccy/bigquery-emulator/internal/contentdata.(*Repository).Query(0x0, {0x3278918, 0xc000fb79b0}, 0xc000fe3ad0, {0xc00024c28b, 0xc0011e43c0}, {0x0, 0xc0002bcd60}, {0xc0009c100a, 0xa5a}, ...)
	:170 +0x68b fp=0xc0002bccc8 sp=0xc0002bc8b0 pc=0x17762eb
github.com/goccy/bigquery-emulator/server.(*jobsInsertHandler).Handle(0xc0002bcfb8, {0x3278918, 0xc000fb79b0}, 0xc0002bcfc8)
	/mnt/hgfs/Fuzz/bigquery-emulator/server/handler.go:1402 +0x518 fp=0xc0002bcf20 sp=0xc0002bccc8 pc=0x17faef8
github.com/goccy/bigquery-emulator/server.(*jobsInsertHandler).ServeHTTP(0x2d35400, {0x323a808, 0xc000e040e0}, 0xc000301d00)
	/mnt/hgfs/Fuzz/bigquery-emulator/server/handler.go:1011 +0x31d fp=0xc0002bcff0 sp=0xc0002bcf20 pc=0x17f667d
github.com/goccy/bigquery-emulator/server.withRoutineMiddleware.func1.1({0x323a808, 0xc000e040e0}, 0xc000301c00)
	/mnt/hgfs/Fuzz/bigquery-emulator/server/middleware.go:287 +0x362 fp=0xc0002bd0b0 sp=0xc0002bcff0 pc=0x1812ca2
net/http.HandlerFunc.ServeHTTP(0x2d35400, {0x323a808, 0xc000e040e0}, 0x8)
	:2047 +0x2f fp=0xc0002bd0d8 sp=0xc0002bd0b0 pc=0x6a34cf
github.com/goccy/bigquery-emulator/server.withModelMiddleware.func1.1({0x323a808, 0xc000e040e0}, 0xc000301b00)
	/mnt/hgfs/Fuzz/bigquery-emulator/server/middleware.go:264 +0x362 fp=0xc0002bd198 sp=0xc0002bd0d8 pc=0x1812742
net/http.HandlerFunc.ServeHTTP(0x2d35400, {0x323a808, 0xc000e040e0}, 0x8)
	:2047 +0x2f fp=0xc0002bd1c0 sp=0xc0002bd198 pc=0x6a34cf
github.com/goccy/bigquery-emulator/server.withTableMiddleware.func1.1({0x323a808, 0xc000e040e0}, 0xc000301a00)
	/mnt/hgfs/Fuzz/bigquery-emulator/server/middleware.go:241 +0x362 fp=0xc0002bd280 sp=0xc0002bd1c0 pc=0x18121e2
net/http.HandlerFunc.ServeHTTP(0x2d35400, {0x323a808, 0xc000e040e0}, 0x6)
	:2047 +0x2f fp=0xc0002bd2a8 sp=0xc0002bd280 pc=0x6a34cf
github.com/goccy/bigquery-emulator/server.withJobMiddleware.func1.1({0x323a808, 0xc000e040e0}, 0xc000301900)
	/mnt/hgfs/Fuzz/bigquery-emulator/server/middleware.go:218 +0x362 fp=0xc0002bd368 sp=0xc0002bd2a8 pc=0x1811c82
net/http.HandlerFunc.ServeHTTP(0x2d35400, {0x323a808, 0xc000e040e0}, 0xa)
	:2047 +0x2f fp=0xc0002bd390 sp=0xc0002bd368 pc=0x6a34cf
github.com/goccy/bigquery-emulator/server.withDatasetMiddleware.func1.1({0x323a808, 0xc000e040e0}, 0xc000301800)
	/mnt/hgfs/Fuzz/bigquery-emulator/server/middleware.go:195 +0x362 fp=0xc0002bd450 sp=0xc0002bd390 pc=0x1811722
net/http.HandlerFunc.ServeHTTP(0x3278918, {0x323a808, 0xc000e040e0}, 0x509bf90)
	:2047 +0x2f fp=0xc0002bd478 sp=0xc0002bd450 pc=0x6a34cf
github.com/goccy/bigquery-emulator/server.withProjectMiddleware.func1.1({0x323a808, 0xc000e040e0}, 0xc000b88400)
	/mnt/hgfs/Fuzz/bigquery-emulator/server/middleware.go:172 +0x37e fp=0xc0002bd548 sp=0xc0002bd478 pc=0x181111e
net/http.HandlerFunc.ServeHTTP(0x3278918, {0x323a808, 0xc000e040e0}, 0x509bf90)
	:2047 +0x2f fp=0xc0002bd570 sp=0xc0002bd548 pc=0x6a34cf
github.com/goccy/bigquery-emulator/server.withServerMiddleware.func1.1({0x323a808, 0xc000e040e0}, 0xc000b88300)
	/mnt/hgfs/Fuzz/bigquery-emulator/server/middleware.go:90 +0x271 fp=0xc0002bd5e8 sp=0xc0002bd570 pc=0x18067d1
net/http.HandlerFunc.ServeHTTP(0xc00143a0f0, {0x323a808, 0xc000e040e0}, 0x4d96580)
	:2047 +0x2f fp=0xc0002bd610 sp=0xc0002bd5e8 pc=0x6a34cf
github.com/goccy/bigquery-emulator/server.decompressMiddleware.func1.1({0x323a808, 0xc000e040e0}, 0xc000b88300)
	/mnt/hgfs/Fuzz/bigquery-emulator/server/middleware.go:71 +0xb6 fp=0xc0002bd6a8 sp=0xc0002bd610 pc=0x1810a76
net/http.HandlerFunc.ServeHTTP(0x2fda928, {0x323a808, 0xc000e040e0}, 0xc000786300)
	:2047 +0x2f fp=0xc0002bd6d0 sp=0xc0002bd6a8 pc=0x6a34cf
github.com/goccy/bigquery-emulator/server.accessLogMiddleware.func1.1({0x323a808, 0xc000e040e0}, 0xc000b88300)
	/mnt/hgfs/Fuzz/bigquery-emulator/server/middleware.go:57 +0x251 fp=0xc0002bd7a0 sp=0xc0002bd6d0 pc=0x18108d1
net/http.HandlerFunc.ServeHTTP(0x3278918, {0x323a808, 0xc000e040e0}, 0x509bf90)
	:2047 +0x2f fp=0xc0002bd7c8 sp=0xc0002bd7a0 pc=0x6a34cf
github.com/goccy/bigquery-emulator/server.loggerMiddleware.func1.1({0x323a808, 0xc000e040e0}, 0xc000b88200)
	/mnt/hgfs/Fuzz/bigquery-emulator/server/middleware.go:45 +0x273 fp=0xc0002bd840 sp=0xc0002bd7c8 pc=0x1806393
net/http.HandlerFunc.ServeHTTP(0x10000c000e83888, {0x323a808, 0xc000e040e0}, 0x4172b4)
	:2047 +0x2f fp=0xc0002bd868 sp=0xc0002bd840 pc=0x6a34cf
github.com/goccy/bigquery-emulator/server.recoveryMiddleware.func1.1({0x323a808, 0xc000e040e0}, 0xc00022e360)
	/mnt/hgfs/Fuzz/bigquery-emulator/server/middleware.go:36 +0x9b fp=0xc0002bd8d0 sp=0xc0002bd868 pc=0x1805dbb
net/http.HandlerFunc.ServeHTTP(0xc000e83920, {0x323a808, 0xc000e040e0}, 0x2ed6ce0)
	:2047 +0x2f fp=0xc0002bd8f8 sp=0xc0002bd8d0 pc=0x6a34cf
github.com/goccy/bigquery-emulator/server.sequentialAccessMiddleware.func1.1({0x323a808, 0xc000e040e0}, 0xc00143a210)
	/mnt/hgfs/Fuzz/bigquery-emulator/server/middleware.go:21 +0xe4 fp=0xc0002bd970 sp=0xc0002bd8f8 pc=0x1805b04
net/http.HandlerFunc.ServeHTTP(0xc000b88100, {0x323a808, 0xc000e040e0}, 0x50468c0)
	:2047 +0x2f fp=0xc0002bd998 sp=0xc0002bd970 pc=0x6a34cf
github.com/gorilla/mux.(*Router).ServeHTTP(0xc00021fe00, {0x323a808, 0xc000e040e0}, 0xc000b88000)
	:210 +0x1cf fp=0xc0002bdac0 sp=0xc0002bd998 pc=0x176c38f
net/http.serverHandler.ServeHTTP({0x32372f8}, {0x323a808, 0xc000e040e0}, 0xc000b88000)
	:2879 +0x43b fp=0xc0002bdb80 sp=0xc0002bdac0 pc=0x6a6a3b
net/http.(*conn).serve(0xc0008b2000, {0x3278918, 0xc00086c4e0})
	:1930 +0xb08 fp=0xc0002bdfb8 sp=0xc0002bdb80 pc=0x6a25a8
net/http.(*Server).Serve·dwrap·87()
	:3034 +0x2e fp=0xc0002bdfe0 sp=0xc0002bdfb8 pc=0x6a738e
runtime.goexit()
	:1581 +0x1 fp=0xc0002bdfe8 sp=0xc0002bdfe0 pc=0x46ef41
created by net/http.(*Server).Serve
	:3034 +0x4e8

goroutine 1 [chan receive, 1470 minutes]:
main.runServer({0xc000072678, 0x417607, 0x188}, {{0x7ffeb8c42374, 0x10}, {0x0, 0x0}, 0x235a, 0x2364, {0x2d47ab7, ...}, ...})
	/mnt/hgfs/Fuzz/bigquery-emulator/cmd/bigquery-emulator/main.go:136 +0x5cf
main.run()
	/mnt/hgfs/Fuzz/bigquery-emulator/cmd/bigquery-emulator/main.go:58 +0x198
main.main()
	/mnt/hgfs/Fuzz/bigquery-emulator/cmd/bigquery-emulator/main.go:42 +0x19

goroutine 5 [select, 2 minutes]:
go.opencensus.io/stats/view.(*worker).start(0xc0000cc080)
	:292 +0xb9
created by go.opencensus.io/stats/view.init.0
	:34 +0x92

goroutine 7 [select, 1470 minutes]:
database/sql.(*DB).connectionOpener(0xc0000a7d40, {0x3278870, 0xc00004fcc0})
	:1196 +0x93
created by database/sql.OpenDB
	:794 +0x188

goroutine 8 [select, 1470 minutes]:
database/sql.(*DB).connectionOpener(0xc0000a7ee0, {0x3278870, 0xc00004fd40})
	:1196 +0x93
created by database/sql.OpenDB
	:794 +0x188

goroutine 911453 [IO wait]:
internal/poll.runtime_pollWait(0x7f30ec658180, 0x72)
	:303 +0x85
internal/poll.(*pollDesc).wait(0xc00092c000, 0xc00143a0a1, 0x0)
	:84 +0x32
internal/poll.(*pollDesc).waitRead(...)
	:89
internal/poll.(*FD).Read(0xc00092c000, {0xc00143a0a1, 0x1, 0x1})
	:167 +0x25a
net.(*netFD).Read(0xc00092c000, {0xc00143a0a1, 0x0, 0xc000a4eef0})
	:56 +0x29
net.(*conn).Read(0xc000be4000, {0xc00143a0a1, 0xc000a4ef88, 0x40f3fd})
	:183 +0x45
net/http.(*connReader).backgroundRead(0xc00143a090)
	:672 +0x3f
created by net/http.(*connReader).startBackgroundRead
	:668 +0xcf

goroutine 911456 [chan receive]:
database/sql.(*Tx).awaitDone(0xc00075bc00)
	:2148 +0x31
created by database/sql.(*DB).beginDC
	:1864 +0x247

goroutine 23 [IO wait]:
internal/poll.runtime_pollWait(0x7f30ec658810, 0x72)
	:303 +0x85
internal/poll.(*pollDesc).wait(0xc000e14000, 0x421386, 0x0)
	:84 +0x32
internal/poll.(*pollDesc).waitRead(...)
	:89
internal/poll.(*FD).Accept(0xc000e14000)
	:402 +0x22c
net.(*netFD).accept(0xc000e14000)
	:173 +0x35
net.(*TCPListener).accept(0xc000e10030)
	:140 +0x28
net.(*TCPListener).Accept(0xc000e10030)
	:262 +0x3d
net/http.(*Server).Serve(0xc000e04000, {0x323a5f8, 0xc000e10030})
	:3002 +0x394
github.com/goccy/bigquery-emulator/server.(*Server).Serve.func2()
	/mnt/hgfs/Fuzz/bigquery-emulator/server/server.go:235 +0x25
golang.org/x/sync/errgroup.(*Group).Go.func1()
	:75 +0x64
created by golang.org/x/sync/errgroup.(*Group).Go
	:72 +0xa9

goroutine 22 [IO wait, 1470 minutes]:
internal/poll.runtime_pollWait(0x7f30ec658720, 0x72)
	:303 +0x85
internal/poll.(*pollDesc).wait(0xc000e14080, 0xc000076c00, 0x0)
	:84 +0x32
internal/poll.(*pollDesc).waitRead(...)
	:89
internal/poll.(*FD).Accept(0xc000e14080)
	:402 +0x22c
net.(*netFD).accept(0xc000e14080)
	:173 +0x35
net.(*TCPListener).accept(0xc000e10048)
	:140 +0x28
net.(*TCPListener).Accept(0xc000e10048)
	:262 +0x3d
google.golang.org/grpc.(*Server).Serve(0xc000e08000, {0x323a5f8, 0xc000e10048})
	:824 +0x477
github.com/goccy/bigquery-emulator/server.(*Server).Serve.func1()
	/mnt/hgfs/Fuzz/bigquery-emulator/server/server.go:234 +0x25
golang.org/x/sync/errgroup.(*Group).Go.func1()
	:75 +0x64
created by golang.org/x/sync/errgroup.(*Group).Go
	:72 +0xa9

goroutine 21 [semacquire, 1470 minutes]:
sync.runtime_Semacquire(0xc000d39d40)
	:56 +0x25
sync.(*WaitGroup).Wait(0xc000e10078)
	:130 +0x71
golang.org/x/sync/errgroup.(*Group).Wait(0xc000e0a040)
	:53 +0x27
github.com/goccy/bigquery-emulator/server.(*Server).Serve(0xc0007a8e70, {0xc0001a6008, 0x301aaaa}, {0xc00087e020, 0xc}, {0xc00087e030, 0xc})
	/mnt/hgfs/Fuzz/bigquery-emulator/server/server.go:236 +0x293
main.runServer.func2()
	/mnt/hgfs/Fuzz/bigquery-emulator/cmd/bigquery-emulator/main.go:132 +0x1f5
created by main.runServer
	/mnt/hgfs/Fuzz/bigquery-emulator/cmd/bigquery-emulator/main.go:127 +0x5b1

goroutine 20 [chan receive, 1470 minutes]:
main.runServer.func1()
	/mnt/hgfs/Fuzz/bigquery-emulator/cmd/bigquery-emulator/main.go:118 +0x47
created by main.runServer
	/mnt/hgfs/Fuzz/bigquery-emulator/cmd/bigquery-emulator/main.go:116 +0x4a5

goroutine 19 [syscall, 1470 minutes]:
os/signal.signal_recv()
	:169 +0x98
os/signal.loop()
	:24 +0x19
created by os/signal.Notify.func1.1
	:151 +0x2c

goroutine 911455 [chan receive]:
database/sql.(*Tx).awaitDone(0xc00075bb80)
	:2148 +0x31
created by database/sql.(*DB).beginDC
	:1864 +0x247

```
:::

## 2023/05/18
:::info
* 針對修改的部分寫測試，並看 coverage
* 嘗試測試整個流程的狀況
:::

## 2023/05/17
:::info
以初始環境( 加上參數`--bootstrap` )測試 Cron：
* /build-crash-stats：使用正常，回傳 OK
* /fuzzer-stats/preload：使用正常，回傳 OK
* /fuzzer-and-job-weights：使用正常，回傳 OK
* /fuzz-strategy-selection：使用正常，回傳 OK
* /load-bigquery-stats：雖然回傳 OK，但當 Bigquery Emulator 重開後，再發一次"**有時**"候會直接卡死(不明原因)，需重開 ClusterFuzz 才變回正常!

:::

## 2023/05/11 (Meeting)
:::info
* 針對已修改的 cron 做測試(local thread 以及以 cron service 測試)
* 現在因為 jobs.query 無法建立 job，所以可以嘗試自己修正並開 PR
:::

## 2023/05/08
:::info
實作 [cron service](https://github.com/ntutselab/cron_service)
* 現在可以以 crom.yaml 上的時間來發 request 至 app engine
  ```python
  # (hour, minute, tartet)
  daily_crons = (
      (1, 47, "/backup"),
      (18, 30, "/fuzzer-coverage"),
      (4, 30, "/fuzzer-stats/preload"),
      (3, 0, "/fuzzer-and-job-weights"),
      (5, 0, "/fuzz-strategy-selection"),
      (1, 0, "/fload-bigquery-stats"),
      (19, 0, "/schedule-corpus-pruning"),
      (9, 0, "/schedule-impact-tasks"),
      # (9, 0, "/schedule-ml-train-tasks"), # tuesday
      (7, 0, "/schedule-progression-tasks"), # timezone: US/Pacific
      (5, 0, "/fuzz-strategy-selection"),
  )

  # (second, target)
  crons = (
      (30 * 60, "/batch-fuzzer-jobs"),
      (5 * 60, "/build-crash-stats"),
      (1 * 60, "/cleanup"),
      (7 * 60, "/fuzzer-stats/cache"),
      (30 * 60, "/manage-vms"),
      (3 * 3600, "/schedule-upload-reports-tasks"),
      (5 * 60, "/predator-pull"),
      (7 * 60, "/testcases/cache"),
      (1 * 3600, "/triage"),
      (1 * 3600, "/sync-admins"),
  )
  ```
* 有一個`/schedule-progression-tasks`指定 Timezone 是 US/Pacific
* 有一個是`schedule-ml-train-tasks`因為設定的日期為 Tuesday 發送，暫時先不加入 cron service 中
* 與其他寫死在 [run_server.py](https://github.com/ntutselab/clusterfuzz/blob/3c6d5532854e172de772b18f18ea1fcb84fde7fb/src/local/butler/run_server.py#L86-L116) 中的四個衝突：
  * 每幾秒鐘執行(可以暫時從 cron_service 中去掉)：
    * cleanup
    * triage
  * 特定時間執行：
    * schedule-progression-tasks
    * schedule-corpus-pruning
:::

## 2023/05/06
:::info
關於 Bigquery Emulator 的 jobs.query 無法產生 job 解法：
* 原先是使用 jobs.insert 來取代 query ，並使用 jobs.getQueryResult 來解決 jobs.insert 回傳 body 與 jobs.query 不相同的問題
* 但發現 obs.getQueryResult 與 jobs.query 還是有些微差異！差在 SessionInfo 以及 DmlStats
* 最後實測後發現其實 Bigquery Emulator 對於 getQueryResult 以及 query 兩者是回傳相同 Data，所以確認兩者回傳 body 相同(僅限 Bigquery Emulator)
  ![](https://hackmd.io/_uploads/BJ1CLKXN2.png)
:::

## 2023/04/25
:::info
關於 Crash_stat 頁面
* 使用莊永推薦的 DSAdmin 查看 build_crash_stat 的數值，發現每次 build 時只會新增一個值，最後發現最開始它只會抓取整個最小的 hour 數，程式如下：
  ```python=79
  ...
  def get_start_hour():
    """Get the start hour from the first crash."""
    client = big_query.Client()

    sql = """
  SELECT min(CAST(FLOOR(UNIX_SECONDS(created_at) / 3600) AS INT64)) as min_hour
  FROM main.crashes
  """

    result = client.query(query=sql)
    if result and result.rows:
      return result.rows[0]['min_hour']

    return 0
  ...
  ```
  因為這個 cron service 會每 5 分鐘跑一次，所以資料是每 5 分鐘新增一筆，所以為了顯示資料，新增一個 method 來 put 資料：
  ```python
  ...
  def insert_all_end_hour():
    sql = "SELECT CAST(FLOOR(UNIX_SECONDS(created_at) / 3600) AS INT64) as min_hour FROM main.crashes"
    client = big_query.Client()
    result = client.query(query=sql)
    for row in result.rows:
      job_history = data_types.BuildCrashStatsJobHistory()
      job_history.end_time_in_hours = row['min_hour']
      job_history.put()
  ...
  ```
  這樣資料就可以放置 datastore 中
  ![](https://i.imgur.com/icBLm3Z.png)

  
:::
:::info
關於 cron service：
* 在`src/local/butler/run_server.py`中的`L86`是一個`start_cron_threads`的 method。
  會在 Local 端執行 thread 跑 cron service。程式如下：
  ```python=85
  ...
  def start_cron_threads():
    """Start threads to trigger essential cron jobs."""

    request_timeout = 10 * 60  # 10 minutes.

    def trigger(interval_seconds, target):
      """Trigger a cron job."""
      while True:
        time.sleep(interval_seconds)

        try:
          url = 'http://{host}/{target}'.format(
              host=constants.CRON_SERVICE_HOST, target=target)
          request = urllib.request.Request(url)
          request.add_header('X-Appengine-Cron', 'true')
          response = urllib.request.urlopen(request, timeout=request_timeout)
          response.read(60)  # wait for request to finish.
        except Exception:
          continue

    crons = (
        (90, 'cleanup'),
        (60, 'triage'),
        (6 * 3600, 'schedule-progression-tasks'),
        (12 * 3600, 'schedule-corpus-pruning'),
    )

    for interval, cron in crons:
      thread = threading.Thread(target=trigger, args=(interval, cron))
      thread.daemon = True
      thread.start()
  ...
  ```
  這邊程式會以`L106`的 crons 作為定期 task 的 list，其中，前面的數字為每幾秒發送 API，而 API 為後面的字串。
  
  最後會在 run_server 時把這些數值加入 thread 並會與主程式一起 shutdown(L115)，在 L116 執行 thread。
  
  而 thread 會執行 trigger method，裡面則是一個 while 迴圈(L93)，依照間隔時間(L94)傳送 API(L97 至 L102)。
* `cron.yaml`中某些 task 可以直接新增至 crons 中，但某些不行，比如說：
  ```yaml
  - description: Obtain code coverage information from the coverage GCS bucket.
    url: /fuzzer-coverage
    schedule: every day 18:30
    target: cron-service
  ```
  這個 task 因為排程在每天的 18:30 傳送 API，但原方法只能以幾秒傳送一次，並不能直接應用。
:::

## 2023/04/13 (Meeting)
:::info
* 使用 build_crash_stats 讓 crash_stats 頁面顯示正確資料
* 以 cron service 發送 build_crash_stats API
:::

## 2023/04/13
:::info
* 使用 postman 傳送 request，並把 build_crash_stats 改 decorator，讓 local 端也能執行。
* 下方為結果
![](https://i.imgur.com/1foFJVP.png)
* 但他的時間區間怪怪的無法正常顯示！
  ![](https://i.imgur.com/cEyu1aE.png)
  * 上方的錯誤時間區段 ('minHour': 426628, 'maxHour': 426631)
    <font color=darkred>2018-09-02 04:00:00 至 2018-09-02 07:00:00</font>
  * 正確的時間區段應該為 ('minHour': 462267, 'maxHour': 465628)
    <font color=green>2022-09-26 03:00:00 至 2023-02-13 04:00:00</font>

:::

## 2023/04/12
:::info
> [1. App Engine app.yaml reference](https://cloud.google.com/appengine/docs/standard/reference/app-yaml?tab=python)
> [2. Scheduling jobs with cron.yaml](https://cloud.google.com/appengine/docs/standard/scheduling-jobs-with-cron-yaml)
* Cron 的服務是由 App Engine 提供，而 App Engine 是由 config 中的 app.yaml 當作設定檔啟動，而 cron 則是從 config 中的 cron.yaml 設置。
* Cron 會在設置的時間發送 request 給 App Engine，使用的是 HTTP 的 `GET`，其 header 有 `X-Appengine-Cron` 這個 key，ClusterFuzz 以此來判斷這個 request 是否來自 cron service。
:::

## 2023/04/06 (Meeting)
:::info
* 嘗試使用 cron service 執行 build_crash_stats，並測試結果是否與 GCP 相同
* 協助學長測試 SQL statement
:::

## 2023/04/05
:::success
* 自己先針對 Query 到的結果來抓取 max hour 跟 min hour，最後成功顯示 bar chart：
  ![](https://i.imgur.com/p0iuUVm.png)
* 目前除了第一排 Filter 無法使用以及時間問題外，其他現已可以使用！

:::
:::info
* 發現 bar chart 功能其實是從 data_store 中獲取 min 和 max 時間，如下：
  > src\clusterfuzz\_internal\metrics\crash_stats.py
  ```python=216
  ...
  def _get_first_or_last_successful_hour(is_last):
    """Get the first successful hour."""
    order = data_types.BuildCrashStatsJobHistory.end_time_in_hours
    if is_last:
      order = -order

    item = data_types.BuildCrashStatsJobHistory.query().order(order).get()
    if not item:
      return None

    return item.end_time_in_hours
  ...
  ```
  其中 
  * `is_last` 當為 `true` 時是獲取 Max，`false` 是獲取 Min
  * `BuildCrashStatsJobHistory` 為 method，說明為 `Represents the record of build_crash_stats run.`，以此推測，在 build crash stats 時會把一些資料存到 `data_store` 中
* 從 `src\appengine\handlers\cron\build_crash_stats.py` 發現在 `L160` 有存的程式碼：
  ```python=159
  ...
  def build_if_needed():
    """Get the next end hour and decide whether to execute build(). If build()
      succeeds, then record the next end hour."""
    try:
      end_hour = get_next_end_hour()
      build(end_hour)

      job_history = data_types.BuildCrashStatsJobHistory()
      job_history.end_time_in_hours = end_hour
      job_history.put()
      logging.info('CrashStatistics for end_hour=%s is built successfully',
                   crash_stats.get_datetime(end_hour))
      return end_hour
    except TooEarlyException:
      logging.info("Skip building crash stats because it's too early.")

    return None
  ...
  ```
:::

## 2023/04/04
:::success
* 參考莊永的記錄得知，Bigquery Emulator 只有 `jobs.insert` 能夠建立 job，所以在 ClusterFuzz bigquery 的 raw_query 使用的 `jobs.query` method 改用 `jobs.insert` 來進行，最後成功使用 `jobs.insert` 達到與 `jobs.query` 相同效果。
* 以下為 big_query.py 的 raw_query 改動後的程式碼：
  ```python
    body = {
      'configuration': {
        'query': {
          'query': query,
          'allowLargeResults': True,
          'useLegacySql': False
        }
      },
      'jobReference': {
        'projectId': self.project_id
      }
    }

    return self.client.jobs().insert(
        projectId=self.project_id, body=body).execute()
  ```
:::

## 2023/03/30 (Meeting)
:::info
* 嘗試讓 ClusterFuzz 的 Crash Stat 頁面條狀圖顯示正常
:::

## 2023/03/29
:::success
* 已成功把 Bigquery Emulator(這邊使用的是有修改過 query 的，為了讓 job 可以成功生成) 套用至 ClusterFuzz 上，並且顯示 crash-stats 的資料
  ![](https://i.imgur.com/jzN5MYB.png)
  其中會發現 bar chart 並沒有顯示，猜測是因為時間問題(PARTITIONTIME)！
:::

:::info
* 以下為讓其顯示的條件：
  * Bigquery Emulator 需啟動(<font color=RED>需要使用修改後的 Emulator，讓 job 能夠成功建立！</font>)，並使用 crash_stats 的 data.yaml (project 名設成 test)
  * 修改 ClusterFuzz BigQuery (src/clusterfuzz/_internal/google_cloud_utils/big_query.py)
    * 最前面新增
      ```python
      from google.api_core.client_options import ClientOptions
      from google.auth.credentials import AnonymousCredentials
      ```
    * 把 get_api_client 這個 method 修改成如下
      ```python
      def get_api_client(ipAddr):
        """Return an api client for bigquery."""
        return discovery.build(
            'bigquery',
            'v2',
            cache_discovery=False,
            credentials=AnonymousCredentials(),
            client_options=ClientOptions(api_endpoint="http://127.0.0.1:9050"))
      ```
    * 把 convert_row 這個 method 的 `if field['mode'] == 'REPEATED':` 改成
      ```python
      if 'mode' in field.keys() and field['mode'] == 'REPEATED':
      ```
    * 把 Client() 中的 `__init__` 下的 `self.ProjectId` 改成 Bigquery Emulator 設定的 Project Name
      ```python
        self.project_id = 'test'
      ```
      
  * 修改 appengine 的 crash_stat 頁面(src/appengine/handlers/crash_stats.py)
    * 把 class Handler 中 get 的 annotation `@handler.unsupported_on_local_server` 去掉
    
  * 修改 SQL (src/clusterfuzz/_internal/metrics/crash_stats.py)
    * 把上面 SQL 語句中的 where {clause} 刪除(在第一個 SELECT 中) 
    * 把底下的 SQL format 中 clause 欄位刪除
:::

## 2023/03/26
:::warning
* 在 ClusterFuzz 的 big_query.py L89 會因為 Emulator 回傳中沒有 `mode` 這個參數，導致錯誤！
```python=88
    field = fields[index]
    if field['mode'] == 'REPEATED':
      row[field['name']] = []
      for item in raw_value['v']:
        row[field['name']].append(cast(item['v'], field))
    else:
      row[field['name']] = cast(raw_value['v'], field)
```
* 只有在 RECORD Type 會有，如下：
  ```json
  "schema": {
      "fields": [
          {"name": "project", "type": "STRING"},
          {"name": "crash_type", "type": "STRING"},
          {"name": "crash_state", "type": "STRING"},
          {"name": "security_flag", "type": "BOOLEAN"},
          {"name": "total_count", "type": "INTEGER"},
          {"name": "min_crash_time_in_ms", "type": "INTEGER"},
          {"name": "max_crash_time_in_ms", "type": "INTEGER"},
          {"name": "sum_crash_time_in_ms", "type": "INTEGER"},
          {"name": "sum_square_crash_time_in_ms", "type": "INTEGER"},
          {"name": "is_new", "type": "BOOLEAN"},
          {"name": "is_reproducible", "type": "BOOLEAN"},
          {"name": "first_index", "type": "INTEGER"},
          {
              "fields": [
                  {"name": "name", "type": "STRING"},
                  {
                      "fields": [
                          {"name": "index", "type": "INTEGER"},
                          {"name": "is_new", "type": "BOOLEAN"},
                          {"name": "percent", "type": "INTEGER"},
                          {"name": "count", "type": "INTEGER"},
                      ],
                      "mode": "REPEATED",
                      "name": "indices",
                      "type": "RECORD",
                  },
              ],
              "mode": "REPEATED",
              "name": "groups",
              "type": "RECORD",
          },
      ]
  },
  ```
* 現在解法：L89 判斷式改成
  ```python=89
  if 'mode' in field.keys() and field['mode'] == 'REPEATED': 
  ```
:::

## 2023/03/23 (Meeting)
:::info
* 嘗試帶入 Bigquery Emulator 使 ClusterFuzz 的 Crash Stats
:::

## 2023/03/16 (Meeting)
:::info 
* 嘗試從 crashes -> crash_stat
* Bigquery Emulator 的 Record type 問題
:::

## 2023/03/16
:::success
* 已成功讓 Bigquery Emulaotr 的 jobs.query 建立 job，如下圖：
  ![](https://i.imgur.com/cdBKXRj.png)
  再 DB 中也能成功看到 job，因為 Emulator 對其資料做 base64 編碼，所以需解碼後才能知道內容。
  ```
  eyJoZWFkZXIiOiJzdHJpbmciLCJib2R5IjoidEMzcWp3bjVvTDRibldCVWRVQTlPUWhFb0Z2In0=
  -> {"header":"string","body":"tC3qjwn5oL4bnWBUdUA9OQhEoFv"}
  
  eyJoZWFkZXIiOiJzdHJpbmciLCJib2R5Ijoie1wiam9iUmVmZXJlbmNlXCI6e1wiam9iSWRcIjpcInRDM3Fqd241b0w0Ym5XQlVkVUE5T1FoRW9GdlwiLFwicHJvamVjdElkXCI6XCJ0ZXN0XCJ9LFwic2NoZW1hXCI6e1wiZmllbGRzXCI6W3tcIm5hbWVcIjpcIk5hbWVcIixcInR5cGVcIjpcIlNUUklOR1wifSx7XCJuYW1lXCI6XCJOdW1iZXJcIixcInR5cGVcIjpcIlNUUklOR1wifV19LFwicm93c1wiOlt7XCJmXCI6W3tcInZcIjpcIkFsaWNlXCJ9LHtcInZcIjpcIjFcIn1dfSx7XCJmXCI6W3tcInZcIjpcIkJvYlwifSx7XCJ2XCI6XCIyXCJ9XX1dLFwidG90YWxSb3dzXCI6XCIyXCIsXCJqb2JDb21wbGV0ZVwiOnRydWV9In0=
  -> {"header":"string","body":"{\"jobReference\":{\"jobId\":\"tC3qjwn5oL4bnWBUdUA9OQhEoFv\",\"projectId\":\"test\"},\"schema\":{\"fields\":[{\"name\":\"Name\",\"type\":\"STRING\"},{\"name\":\"Number\",\"type\":\"STRING\"}]},\"rows\":[{\"f\":[{\"v\":\"Alice\"},{\"v\":\"1\"}]},{\"f\":[{\"v\":\"Bob\"},{\"v\":\"2\"}]}],\"totalRows\":\"2\",\"jobComplete\":true}"}
  ```
* Golang 在 rebuild 時會只 build 修改的地方，速度會比一開始 build 時要快。
:::

## 2023/03/14
:::warning
* 可能存在的問題：當在做 Query 的時候(發 jobs.insert 這個 API 也會用到)，Bigquery Emulator 會持續 Query，直到 Query 完成後才會把 job 新增至 project 中...
* 此問題是在分析 handler 時發現的，以 jobsInsertHandler 為例：
  ```go=1337
    ...
  func (h *jobsInsertHandler) Handle(ctx context.Context, r *jobsInsertRequest) (*bigqueryv2.Job, error) {
    job := r.job
    ...
  ```
  jobs.insert 的 Request Body 中，本身會包含一個 job instance，所以在 `L1339` 持續使用這個 instance。
  
  再經過一些判斷後到 `L1371` Query 的部分，**注意**，此時都還沒新增一個 job 至 project 中。
  ```go=1369
  ...
  startTime := time.Now() // 記錄開始 Query 的時間
  response, jobErr := r.server.contentRepo.Query(
    ctx,
    tx,
    r.project.ID,
    "",
    job.Configuration.Query.Query, // 使用 job 中的 Query 語句(SQL)
    job.Configuration.Query.QueryParameters,
  )
  endTime := time.Now() // 記錄結束 Query 的時間
  ...
  ```
  從上面的開始以及結束時間可以知道，Query 期間並沒有 job，所以當大量資料 Query 時，會因系統效能 delay，而且也無法查看 job 狀況！
  
  最後才會新增 job 至 project 中，`L1432` 使用 project 的 AddJob method，`L1435` 以 parameter 回傳一個新的 job
  ```go=1431
  ... 
  if err := r.project.AddJob(
    ctx,
    tx.Tx(),
    metadata.NewJob( // 回傳一個新的 job
      r.server.metaRepo,
      r.project.ID,
      job.JobReference.JobId,
      job,
      response,
      jobErr,
    ),
  ); err != nil {
    return nil, fmt.Errorf("failed to add job: %w", err)
  }
  ...
  ```

* 在 ClusterFuzz Bigquery 中就我的理解 Query 與 job 的流程如下：
  
  * Query request
  * 建立 job
  * 做 Query
  * 完成 Query 時，改變 job status，並把 Query 到的 data 存至 job 中
  
  以上步驟可以讓使用者在 Query 期間查看 Query status，當 status 為 DONE 時，即完成 Query 並可以接受 data。
  
* 在 Bigquery Emulator 中流程如下：
  
  * Query request (不僅限於 Query，Insert 又或是其他會建立 job 的 API 都是相同)
  * 做 Query
  * 完成 Query
  * 建立 job

  以上步驟在 Query 完成前是無法得知 Query 狀況，當收到 response 時即完成 Query。
:::

## 2023/03/09 (Meeting)
:::info
* 嘗試把 jobs.insert Handler 中的 job 部分複製到 jobs.query Handler 中
* 幫忙學長把 ClusterFuzz 使用到的 SQL statement 條列出來
:::

## 2023/03/08
:::success
* 成功建置 Bigquery Emulator，使用 go 版本為 1.17
  1. Clone Bigquery Emulator 專案，Build 前需安裝 clang (成功建置的版本為 16.0.0)
  2. cd 至專案中
  3. 輸入 `make emulator/build` (請確認呼叫 clang++ 的指令，初始為 clang++，若不相同可以直接修改 makefile 中 clang++ 的部分)
  4. 等待 (此專案 Build 需花費很多時間！)
  5. 如果專案中出現 `bigquery-emulator` 的執行檔即 Build 成功
     可以使用 `./bigquery-emulator -h` 確認是否正常
* 如果有 <font color="#F00000">`Killed signal terminated program cc1plus`</font> 的問題，請嘗試提高記憶體限制，又或是關閉其他軟體。
:::

## 2023/03/03
:::info
* 嘗試安裝 Emulator 在 VMware，嘗試過 golang
  * 1.20.1
  * 1.16.15
  * 1.18
  
  後來發現在 Bigquery Emulator 的 go.mod 中，有作者使用的 go 版本，為 `1.17`！
* 初步認為安裝時發生的錯誤，除了某些錯誤是因為記憶體不夠外，還有一些錯誤可能是因為 golang 的 dependency 問題，建議使用與專案相同的 golang。
:::

## 2023/03/02(Meeting)
:::info
* 分析在 ClusterFuzz 中，使用到 Bigquery Query 的地方(有使用到 SQL 的)
* 建置 Bigquery Emulator 方便日後修正 Bug
* 
:::

## 2023/02/23(Meeting)
:::info
* 嘗試建立 go-zetasqlite
* Trace Bigquery Emulator 在哪邊建立 Job
* 嘗試修改 ClusterFuzz Bigquery 在 raw_query 的 body
:::

## 2023/02/23
:::info
* Client 建構方式有兩種：
  * 以 discovery 建構 client (googleapiclient.discovery)
  * 以 bigquery 建構 client (google.cloud.bigquery)
* 使用 discovery 的方式建構 client，有蠻多 bug 的問題
* 使用 google.cloud.bigquery 的方式建構 client，因為是 bigquery emulator 預設使用的方式，經過測試到現在，沒發現其他問題。
:::

:::warning
* 開啟 Bigquery Emulator 時，並沒有對原本 Database 做讀取，導致發 REST API 時，Dataset、Table 以及 Jobs 是空的，即某些資料並無法從上次的狀態繼承(不過使用 SQL 是可行的)。
:::

## 2023/02/15(Meeting)
:::info
* BigQuery Emulator 與 ClusterFuzz Bigquery 比較
:::

## 2023/02/14
:::info
* 重啟 BigQuery Emulator 後，原先的 Dataset 與 Table 雖然用 SQL 語法還是能 Query 到，但以 REST API 來 Query 會 not found，必須新建立一個 Dataset 或 Table。
* 假設要使用 [insertAll](https://cloud.google.com/bigquery/docs/reference/rest/v2/tabledata/insertAll) 就需要確認 [Dataset](https://cloud.google.com/bigquery/docs/reference/rest/v2/datasets/list) 與 [Table](https://cloud.google.com/bigquery/docs/reference/rest/v2/tables/list) 是否存在，才能使用 insertAll。
:::

:::warning
* 照 ClusterFuzz BigQuery 的方式使用 insertAll，進去的資料 value 會是 **None**，不過能夠確定 insertAll 是可以使用的(因為資料有增加)。
:::

## 2023/02/02
:::info
* 透過 bigquery.Client() 建立 client，並使用 client.query() 來查詢，發現 job 會因此被建立起來，並且能在 Database 以及 BigQuery REST API 中看到 job。
  > https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/list
  > 
  ![](https://i.imgur.com/zLMgV17.png)
  ![](https://i.imgur.com/OStR85q.png)
* 透過上述方式可以建立 job，以上面的 jobId 可以使用 BigQuery REST API 來獲得 job 的 result。
  ![](https://i.imgur.com/YBpHiWC.png)
:::

:::warning
* 使用 discovery 建立 client，並使用 client.jobs().query() 的方式無法產生 job，需要再研究兩者差異！
* 在 ClusterFuzz 中，BigQuery 先做 Query，在使用 jobId 確認 Job 狀況。當完成時，就會把 result 再做處理，這之中都是以第一次 Query 產生的 jobId 來處理。換成以 BigQuery Emulator 來做時，第一次的 Query 卻並沒有產生 job，以至於後續操作錯誤，產生 job not found 的錯誤訊息！
:::

## 2023/02/01
:::info
* 在 ClusterFuzz 中，BigQuery 使用 jobs 的方式來對其做動作
  * jobs 可以視為一個作業操作，包括 Loading、Exporting、Querying 或 Copying Data。
  * 每個 job 會有一個獨特的 jobId，利用這個 jobId 可以把未完成的操作接續下去又或是進行其他的操作！
  * jobs 的目的：某些操作會需要花費較長的時間，透過輪詢 Polling 的方式確認其 Status。
  > 以上參考 [GCP BigQuery 對 Jobs 的說明](https://cloud.google.com/bigquery/docs/jobs-overview)
* 在 ClusterFuzz 中，BigQuery 在 query 的動作如下(從原始碼中得知)：
  * 執行 jobs.query() 獲取 jobId
  * 再以 jobId 執行 insert, insertAll, getQueryResults, get ...
:::

:::success
* google api client 中的 discovery(與 ClusterFuzz BigQuery 相同用法) 是可以使用在 BigQuery Emulator 上。
* 在 BigQuery Emulator 中，可以使用與 ClusterFuzz 相同方式透過 `jobs.query()` 以 SQL 方式使用 job 來獲取資料！
:::

:::warning
* 在 BigQuery Emulator 中，使用 jobs.query() 獲取的 jobId 能正常產生，但後續要再使用這個 job 卻顯示 not found，抓取這個 project 所有 jobs 也是空的！
* 發現 jobs.query() 得到的 jobId 與 jobs.getQueryResults() 需要的 jobId 格式不同：
  * jobs.query() -> pSl7gRP51KKPbdG7XhpMabMTBZO
  * jobs.getQueryResults() -> 3ed17da0-4d53-400c-98c0-0f1f7404fda4
  
  但在 ClusterFuzz 的 BigQuery 中卻可以這樣去執行，第二個才是對的，需要了解為什麼 jobs.query() 會產生這樣的數值(已嘗試使用 Base64 或 base32 等等解碼，但無效)
:::

## 2023/01/12 Meeting
:::info
* 找出 cron 如何啟動
* 嘗試 google client api 的 discovery 套用 Bigquery Emulator 做使用
:::

## 2023/01/12
:::warning
* 無法直接使用 Bigquery Emulator 代替 Biqeury，某些並不支援，比如說：
  * PARTITIONTIME
  * 格式問題：
    ![](https://i.imgur.com/lBCncjs.png)

:::

## 2023/01/11
:::info
* Bigquery Emulator
  * 可以使用 SQL 的 Insert 方式新增資料
    ```SQL
    INSERT INTO (column1, column2) VALUES (Data1, Data2)
    ``` 
  * 內部資料結構為
    ```
    ├⎯ Project 1
    │    ├⎯ Dataset 1.1
    │    │    ├⎯ Table 1.1.1
    │    │    └⎯ Table 1.1.2
    │    ├⎯ Dataset 1.2
    │    │    ├⎯ Table 1.2.1
    │    │    └⎯ Table 1.2.2
    ├⎯ Project 2
    │    ├⎯ Dataset 2.1
    │    │    ├⎯ Table 2.1.1
    │    │    └⎯ Table 2.1.2
    │    ├⎯ Dataset 2.2
    │    │    ├⎯ Table 2.2.1
    │    │    └⎯ Table 2.2.2
    ```
  * Project 建立 DB 後，無法再次新增(需再重新覆蓋才行！)
  * Dataset 與 Table 可以建立 DB 後再新增
    
:::

## 2023/01/05 Meeting
:::info
* Bigquery Emulator 嘗試 Insert 資料進去
* Bigquery Emulator 使用的是 SQLite database，需考慮其效能問題！
* 分析 Redis 與 Datastore 和 Bigquery 之間的資料流向
* 確認是否能夠建立之間的 Emulator
:::

## 2023/01/05

使用 crash_stat 的 SQL 語法來嘗試查詢

## 2023/01/04
以下參考 https://github.com/goccy/bigquery-emulator/tree/main/_examples/python
:::info
開啟 Bigquery Emulator 的方式(Use docker)
* Pull Bigquery Emulator
  ```
  docker pull ghcr.io/goccy/bigquery-emulator:latest
  ```
* cd 至目錄，使用 mount 的方式連結 dataset (記得把 dataset.yaml 放置於目錄中)
  ```
  docker run -it -p 9050:9050 --name bigquery-emulator --mount type=bind,src=$(pwd),target=/work --workdir /work ghcr.io/goccy/bigquery-emulator:latest --project=test --data-from-yaml=/work/data.yaml
  ```
  如果要使用 Database 功能 (即在本地建立 Database)，參數加上 `--database=<DB Name>`
  ```
  docker run -it -p 9050:9050 --name bigquery-emulator --mount type=bind,src=$(pwd),target=/work --workdir /work ghcr.io/goccy/bigquery-emulator:latest --project=test --database=/work/database.db --data-from-yaml=/work/data.yaml
  ```
  
* 之後要啟動時輸入
  ```
  docker start <Contain ID>
  ```
  
  若有包含 Database 功能，需建立不包含 dataset(--data-from-yaml) 參數的 Container
  ```
  docker run -it -p 9050:9050 --name bigquery-emulator --mount type=bind,src=$(pwd),target=/work --workdir /work ghcr.io/goccy/bigquery-emulator:latest --project=test --database=/work/database.db
  ```
  才能夠正常啟動，否則會出現 `Insert Error`
  

使用 Google 的 python library 來連接並獲取資料
* 需要 Python version >= 3.7
* 使用 pipenv 來安裝 dependency (參考[這個連結](https://github.com/goccy/bigquery-emulator/tree/main/_examples/python)的 Pipfile, Pipfile.lock)
  * 建立 Pipfile 與 Pipfile.lock (前者為 install 的 packages，後者為 packages 的 Hash code)
  * 安裝 `pipenv`
    ```
    pip install --upgrade setuptools
    pip install pipenv
    ```
  * 安裝依賴
    ```
    pipenv install
    ```
* 建立 Python script
  ```python
  # example.py
  from google.api_core.client_options import ClientOptions
  from google.auth.credentials import AnonymousCredentials
  from google.cloud import bigquery

  API_ENDPOINT = "http://localhost:9050"
  print(API_ENDPOINT)

  def main():
      client = bigquery.Client(
          'test',
          client_options=ClientOptions(api_endpoint=API_ENDPOINT),
          credentials=AnonymousCredentials(),
      )
      job = client.query(
          query='SELECT * FROM dataset1.table_a',
          job_config=bigquery.QueryJobConfig(),
      )
      print(list(job.result()))

  if __name__ == '__main__':
      main()
  ```
* 最後運行 Python script 在虛擬環境中
  ```
  pipenv run python example.py
  ```
![](https://i.imgur.com/6vQtLIH.png)

:::

---

<div style="font-size:36px;text-align:center;">2022 → 2023</div>
<div style="font-size:36px;text-align:center;">Happy New Year</div>

---

## 之前的紀錄 
[Fuzz 紀錄 2022](https://hackmd.io/@kyL/Fuzz2022)