2022/06/26

PostgreSQLの導入方法(Windows編)


背景


PostgreSQL開発のため、WindowsにPostgreSQLを導入する方法について調査した。

記事の目的


PostgreSQLをWindowsに導入する

PostgreSQL


ここではPostgreSQLについて記載する。

リレーショナルデータベース

リレーショナルデータベースとは、事前定義された、関連があるデータ項目の集合体である。 この項目は、列と行を持つテーブルのセットとして構成される。 テーブルは、データベースに表現されるオブジェクトに関する情報を保持するために使用される。

Windowsへの導入法

WindowsへのPostgreSQL導入方法について記載する。
  1. インストーラのダウンロード
  2. インストーラは EDB社によって提供され、このページからダウンロードできる。
  3. インストーラによるインストール
    1. インストーラの起動
    2. インストール先の選択
    3. インストール内容の選択
    4. データベースデータ保存先の選択
    5. 管理者権限のパスワード設定
    6. データベースへの接続時に必要となる
    7. データベースのポート設定
    8. 完了
  4. 起動状況の確認
    • サービスで起動状況確認
    • ファイル名を指定して実行(R)でservice.mscを起動
    • サービスの起動状態を確認
      右クリックで停止するを選択するとPostgreSQLを停止できる


まとめ


  • WindowsのPostgreSQL導入方法について調査、記載した

参考文献




変更履歴


  1. 2022/06/26: 新規作成

2021/02/07

InfluxDBの導入(Windows編)


背景


InfluxDB開発のため、WindowsにInfluxDBを導入する方法について調査した。

記事の目的


InfluxDBをWindowsに導入する

InfluxDB


ここではInfluxDBについて記載する。

時系列データベース

InfluxDBは時刻情報を主キーとしたデータを扱う時系列データベースの一つである。IoTデバイスのセンサーデータやソフトウェアのログデータなどの時刻情報を付随したデータを扱うことが可能である。

ツール類のサポート

InfluxDBには、PythonやJavascript、Grafanaとの連携がサポートされている。そのため、時系列データの解析や可視化が可能である。

Windowsへの導入法

WindowsへのInfluxDB導入方法について記載する。
  1. InfluxDBのダウンロード
  2. 公式ホームページからInfluxDBをダウンロードする
  3. InfluxDBの解凍
  4. ダウンロードしたZIP形式のファイルを
    C:\Program Files
    に展開する
  5. influxdbのデータ保存先を作成する
    • metadataとraftデータベースの保存先を作成する
    • C:\Program Files\influxdb-X.X.X-X
      にmetaディレクトリを作成
    • TSMファイルの保存先を作成する
    • C:\Program Files\influxdb-X.X.X-X
      にdataディレクトリを作成
    • WALファイルの保存先を作成する
    • C:\Program Files\influxdb-X.X.X-X
      にwalディレクトリを作成
  6. influxdb.confの変更
  7. 設定ファイル(influxdb.conf)を変更する。
    • metadataとraftデータベースの保存先を変更する
    • 変更前
      [meta]
        # Where the metadata/raft database is stored
        dir = "/var/lib/influxdb/meta"
      変更後
      [meta]
        # Where the metadata/raft database is stored
        dir = "C:\Program Files\influxdb-X.X.X-X\meta"
    • TSMファイルとWALファイルの保存先を変更する
    • 変更前
      [data]
        # The directory where the TSM storage engine stores TSM files.
        dir = "/var/lib/influxdb/data"
        # The directory where the TSM storage engine stores WAL files.
        wal-dir = "/var/lib/influxdb/wal"
      変更後
      [data]
        # The directory where the TSM storage engine stores TSM files.
        dir = "C:\Program Files\influxdb-X.X.X-X\data"
        # The directory where the TSM storage engine stores WAL files.
        wal-dir = "C:\Program Files\influxdb-X.X.X-X\wal"
    • http通信の設定確認
    • 下記の通り設定されているか確認
      [http]
        # Determines whether HTTP endpoint is enabled.
        enabled = true
      
        # Determines whether the Flux query endpoint is enabled.
        # flux-enabled = false
      
        # Determines whether the Flux query logging is enabled.
        # flux-log-enabled = false
      
        # The bind address used by the HTTP service.
        bind-address = "localhost:8086"
      
        # Determines whether user authentication is enabled over HTTP/HTTPS.
        auth-enabled = false
      
        # The default realm sent back when issuing a basic auth challenge.
        # realm = "InfluxDB"
      
        # Determines whether HTTP request logging is enabled.
        log-enabled = true
  8. InfluxDBの起動
  9. powershellでInfluxDBを起動する
    PS > cd C:\Program Files\influxdb-X.X.X-X
    PS C:\Program Files\influxdb-X.X.X-X > ./influxd.exe -config influxdb.conf
    
  10. InfluxDBに動作確認
    • influxにアクセス
    • 時刻はrfc3339形式を使用する
      PS > cd C:\Program Files\influxdb-X.X.X-X
      PS C:\Program Files\influxdb-X.X.X-X > ./influx.exe -precision rfc3339
    • DBを作成する
    • > create database sample_database
    • 作成したDBの確認する
    • > show databases
    • 操作するDBを設定する
    • > use sample_database
    • 作成したDBにデータをinsertする
    • > insert sample,tag1=A,tag2=B field1="a",field2="b"
      > insert sample,tag1=C field1="c",field2="d"
      > insert sample,tag1=D,tag2=E field2="e"
      sampleというmeasurement(postgresqlのtable)にtag1, tag2の2つのtag、field1, field2の2つのfieldを挿入した。なお、tag(postgresqlのindex)やfieldは複数指定可能であり、tagやfieldが無い場合はnullとしてinsertされる。
    • 作成したDBにデータをselectする
    • > select * from sample
      name: sample
      time                         field1 field2 tag1 tag2
      ----                         ------ ------ ---- ----
      2021-02-07T09:52:50.0723845Z a      b      A    B
      2021-02-07T10:02:01.4085273Z c      d      C
      2021-02-07T10:02:14.4877153Z        e      D    E
      


データ型

InfluxDBのデータ型は下記の通りである。
データ型 説明
Float 64ビット浮動小数点数。デフォルトの数値型 。
Integer符号付き64ビット整数(-9223372036854775808から9223372036854775807)。数値の末尾にiを付けて整数を指定する。例:1i
String 文字列。Measurements, tag keys, tag values, field keys, field values で使用できる。最大 64KB。
Boolean真偽値。真は [t、T、true、True、TRUE]。 偽は [f、F、false、False、FALSE] で表現する。
Timestamp Unixナノ秒タイムスタンプ。


まとめ


  • WundowsへのInfluxDB導入方法について調査記載した

参考文献




変更履歴


  1. 2021/02/07: 新規作成

2021/01/24

PlantUMLでコンポーネント図作成

背景


システムの詳細設計でコンポーネント図を作成する必要があり、Gitで差分管理が可能なコンポーネント図作成ツールを調査した。

記事の目的


PlantUMLでコンポーネント図を作成する

コンポーネント図


コンポーネント図について記載する。

コンポーネント図とは

コンポーネント図は、システム内のさまざまなコンポーネント間の関係を記述したものである。

コンポーネント図の描き方

  • コンポーネントとインターフェース
  • @startuml
    component Component
    () Interface
    @enduml
    スコープ内の開始と終了を表す。

コンポーネント図作成時の注意点

コンポーネント図作成時は、下記の8つのポイントに注意する。
  • 依存を循環させない (Acyclic Dependencies)
  • コンポーネント間の依存関係を循環させてはならない。たとえば、A→B→C→Aという依存は循環するため、認めてはならない。
  • 共通性で閉じていること (Common Closure)
  • 同じコンポーネント内のクラスは同種の変更に対して全体として閉じていなければならい。ある変更がコンポーネント内の1つのクラスに影響したとしても、その変更がコンポーネント外のクラスに影響を及ぼしてはならない。言い換えると、複数のコンポーネントにまたがる変更が必要にならないよう、コンポーネント内の凝集性を高めておく必要がある。
  • 一緒に再利用されること (Common reuse)
  • コンポーネント内のクラスはまとめて再利用する。コンポーネント内の1つのクラスを再利用する場合には、すべてを再利用する。これも凝集性に関する原則である。
  • 依存の逆転 (Dependency Inversion)
  • 抽象概念は詳細事項に依存してはならないが、詳細事項は抽象概念に依存するべきである。
  • 開いているが、閉じられてもいる (Open-Closed)
  • ソフトウェア要素は拡張に対して開いているが、変更には閉じられていなければならない。
  • リリースと再利用は同じ単位 (Release-Reuse Equivalency)
  • 再利用とリリースは同じ単位で行う。言い換えると、リリースしたソフトウェア要素の一部だけを再利用するべきではない。
  • 安定した抽象化 (Stable Abstractions)
  • コンポーネントは抽象的であり、かつ安定していなければならない。コンポーネントは、安定した状態のまま拡張できるよう、十分に抽象的でなければならない。
  • 安定した依存関係 (Stable Dependencies)
  • より安定したものに対して依存する。たとえば、コンポーネントAがコンポーネントBに依存する場合、AよりもBの方が安定しているべきである(変更の可能性が低いなど)。

まとめ


  • PlantUMLでコンポーネント図を作成する方法を調査、記載した

参考文献



変更履歴


  1. 2020/05/06: 新規作成

2020/07/06

Jestで時刻を固定化する方法


背景


Node.jsで動作するサーバーアプリのユニットテストコードをJestで作成するため、Jestの使用方法について調査した。

記事の目的


Jestで時刻を固定する

Date関数 / moment関数


ここでは、Date関数 / moment関数について記載する。

Date関数とは

Date関数は、Javascript標準の時刻モジュールである。現在時刻の取得などが行える。

moment関数とは

moment関数は、Date関数のラッパーであり、時刻差の計算などの機能が付与されている。

時刻の固定


時刻固定の必要性

ある関数やクラスのユニットテストを実行する際、堅牢性確認のため、閏年や特定の時刻でバグが出現しないか確認する必要がある。

時刻の固定方法

MockDateモジュールで時刻を固定できる。

/test/date.test.ts
import MockDate from "mockdate";
import moment from "moment";

describe("時刻の固定化", () => {
    beforeAll(() => {
        // JSTで時刻を固定できる
        MockDate.set("2019-08-01 21:00:00");
    });

    afterAll(() => {
        // 時刻の固定を解除する
        MockDate.reset();
    });

    test("Dateは固定時刻の文字列を返す", () => {
        const time = new Date();
        expect(time.toISOString()).toBe("2019-08-01T12:00:00.000Z");
    });
    test("momentはDateのラッパーなため、固定時刻を返す", () => {
        expect(moment().toISOString()).toBe("2019-08-01T12:00:00.000Z");
    });
  });

まとめ


  • Jestで時刻を固定する方法について調査、記載した

参考文献




変更履歴


  1. 2020/07/06: 新規作成

2020/07/01

Jestで関数、クラスをMockする方法


背景


Node.jsで動作するサーバーアプリのユニットテストコードをJestで作成するため、Jestの使用方法について調査した。

記事の目的


Jestで関数やクラス全体、クラスのメソッドの一部をMockする

Jest


ここでは、Jestについて記載する。

Jestとは

Jestは、Facebookが開発を進めている、オープンソースのJavaScriptのテストフレームワークである。TypeScriptで記述したものでも利用できる。テストフレームワークであるため、テストを書くために必要な一通りの機能(メソッドのMock機能、コードカバレッジレポート機能等)が提供されている。

Mock


Mockとは

ある関数やクラスのユニットテストを実行する際、それらが依存している外部モジュールの挙動によって実行結果が変化することは不適切である。そこで、外部モジュールを、一定の実行結果がモジュールに差し替える。この差し替えたモジュールをMockと言う。

関数のMock

/src/function.ts
/**
 * 入力した数値を文字列に変換する
 * @param input 数値
 * @returns output 文字列
 **/
export async function SampleFanc(input: number): Promise<string> {
    return String<input>;
}
/**
 * 入力した数値に1を足し、文字列に変換する
 * @param input 数値
 * @returns output 文字列
 **/
export async function SampleFanc2(input: number): Promise<string> {
    const out = SampleFanc(input+1);
    return out;
}
上記の関数sampleFancをMockし、sampleFanc2をテストする場合、下記のようになる。

/test/function.test.ts
import * as sampleFanc from "../src/function.ts";

describe("SampleFancのモック化テスト", () => {
    it("モック化できているか", () => {
        // spyOnすることによって、該当関数(SampleFanc)の型がspyInplementationに変化する
        // mockReturnValueOnce()によって1度だけ設定値を返す関数にMockできる
        // jest.spyOnだけでは、実際の関数(Mockされていない関数)が実行されるので注意
        const sampleSpy = jest.spyOn(sampleFanc , "SampleFanc").mockReturnValueOnce("1");

        // SampleFanc2の実行、返り値が"2"でなければNG
        expect(sampleFanc.sampleFanc2(1)).toBe("2");
        // SampleSpyが1回以上呼ばれたかを確認、呼ばれていない場合NG
        expect(SampleSpy).toHaveBeenCalled();
    });
});
}


クラス全体のMock

/src/class.ts
/**
 * 入力した数値を文字列に変換する
 * @param input 数値
 * @returns output 文字列
 **/
export class SampleClass {
    private data: string;
    /**
     * 空文字列をセット
     */
    constructor() {
        this.data= "";
    }
    /**
     * 入力された文字列をキャッシュし、前の文字列を返す
     * @param input キャッシュする文字列
     * @returns output キャッシュされていた文字列
     */
    public Func1(input: string): string {
        const output = this.data;
        this.data = input;
        return output;
    }
    /**
     * 入力された数値を文字列に変換してキャッシュし、前の文字列を返す
     * @param input キャッシュする数値
     * @returns output キャッシュされていた文字列
     */
    public Func2(input: number): string {
        const output = this.Func1(String(input));
        return output;
    }
}
上記のクラスsampleClassをMockする場合、下記のようになる。

/test/function.test.ts
import * as sampleClass from "../src/class.ts";

// jest.mock()によってクラス全体をモック化できます
jest.mock("../src/class.ts"); // パスを指定
const SampleClassMock = sampleClass.SampleClass as jest.Mock; // TypeScriptでは型変換する必要がある

describe("SampleClass のテスト", () => {
    it("クラス全体がモックになっているか確認", () => {
        // mockImplementationOnceで実装したいクラスを設定する
        SampleClassMock.mockImplementationOnce(() => {
            return {
                data: "1",
                Func1: (): string => {
                    return "2";
                },
                Func2: (): string => {
                    return "3";
                },
            };
        });

        const sample = new sampleClass.SampleClass();
        // SampleClassMockが1度以上呼び出されたか確認
        expect(SampleClassMock).toHaveBeenCalled();
        // プライベート変数"name"が"1"であるか確認
        expect(sample["data"]).toBe("1");
        // メソッドFunc1が"2"を返すか確認
        expect(sample.Func1("1")).toBe("2");
        // メソッドFunc2が"3"を返すか確認
        expect(sample.Func2(1)).toBe("3");
    });
});

クラスの一部をMock

/src/class.ts
/**
 * 入力した数値を文字列に変換する
 * @param input 数値
 * @returns output 文字列
 **/
export class SampleClass {
    private data: string;
    /**
     * 空文字列をセット
     */
    constructor() {
        this.data= "";
    }
    /**
     * 入力された文字列をキャッシュし、前の文字列を返す
     * @param input キャッシュする文字列
     * @returns output キャッシュされていた文字列
     */
    public Func1(input: string): string {
        const output = this.data;
        this.data = input;
        return output;
    }
    /**
     * 入力された数値を文字列に変換してキャッシュし、前の文字列を返す
     * @param input キャッシュする数値
     * @returns output キャッシュされていた文字列
     */
    public Func2(input: number): string {
        const output = this.Func1(String(input));
        return output;
    }
}
上記のクラスsampleClassのFunc1のみをMockする場合、下記のようになる。

/test/function.test.ts
import * as sampleClass from "../src/class";

describe("SampleClass のテスト", () => {
    it("Func1がモックになっているか確認", () => {
        // SampleClass.prototypeのfunc1関数をspyOnすることで、func1関数のモック化ができる
        const Func1Spy = jest.spyOn(sampleClass.SampleClass.prototype, "Func1").mockReturnValue("2");

        const sample = new sampleClass.SampleClass();
        // Func2の実行結果が"2"であるか確認
        expect(sample.Func2(1)).toBe("2");
        // Func1Spy が1度以上呼び出されたか確認
        expect(Func1Spy).toHaveBeenCalled();
    });
});

まとめ


  • Jestで関数やクラス全体、クラスのメソッドの一部をMockする方法について調査、記載した

参考文献




変更履歴


  1. 2020/07/01: 新規作成

MQTTの導入

背景 IoTデバイスの接続環境構築のため、MQTT(mosquitto)の導入を行った。 記事の目的 MQTT(mosquitto)をUbuntuに導入する mosquitto ここではmosquittoについて記載する。 MQTT MQTT(Message Qu...