IT練習ノート

IT関連で調べたこと(実際は嵌ったこと)を書いています。

cabalのreplでテストスイートを使う

Haskellのテストをcabalで行う時は、下記のように実行します。(configureは毎回出なくて大丈夫ですが)

% cabal configure --enable-tests
% cabal build
% cabal test

テストコードを少し書くごとにcabal buildするのは、テストが蓄積されると時間がかかります。テストコードを書いている時に、replでテストコードを試せると便利だと思います。通常では、executablelibraryの依存関係をreplは使っていると思います。そこにテスト関連のライブラリの依存関係はもたせたくないということです。

詳しいことはわかっていないのですが、cabal repl時にTest-Suite名を指定すると、そのテストスイートの依存関係でのreplが起動するようです。

-- Test
Test-Suite MyTestSuite01
  type: exitcode-stdio-1.0
  main-is: MyTest01.hs
  hs-source-dirs: test
                 ,src -- これは余計で、本来は、cabalのname自体をbuild-dependsに書くべき
  ghc-options: -Wall
  build-depends:       base >=4.9 && <4.10
                     , tasty
                     , tasty-hunit
                     , protocol-buffers >=2.4 && <2.5
                     , protocol-buffers-descriptor >=2.4 && <2.5
                     , network
 .. 以下省略

としておいて、

% cabal repl MyTestSuite01

で起動します。

*Main> :l test/MyTest01.hs
*Main> main
my_test_01: FAIL
  1=2 ?
  expected: 1
   but got: 2

1 out of 1 tests failed (0.00s)
*** Exception: ExitFailure 1
*Main>

使ったコードは下記です。

module Main where

import Test.Tasty
import Test.Tasty.HUnit
import System.Exit (exitFailure)

main =defaultMain (testCase "my_test_01" (assertEqual "1=2 ?" 1 2) )

MySQLのmysqlsh(XProtocol)でssl通信ができない -> できているとおもう。

通常のmysqlからはssl通信ができるけど、mysqlshからはできない。なんでだろう。。

追記:たぶん\sではclassic扱いで、xplugin側の設定が表示されないだけだと思う。

foo$ ls /usr/local/var/mysql/*.pem
/usr/local/var/mysql/ca-key.pem       /usr/local/var/mysql/client-cert.pem  /usr/local/var/mysql/private_key.pem  /usr/local/var/mysql/server-cert.pem
/usr/local/var/mysql/ca.pem       /usr/local/var/mysql/client-key.pem   /usr/local/var/mysql/public_key.pem   /usr/local/var/mysql/server-key.pem

foo$ cat ~/.my.cnf
[mysqld]
ssl-ca=/usr/local/var/mysql/ca.pem
ssl-cert=/usr/local/var/mysql/server-cert.pem
ssl-key=/usr/local/var/mysql/server-key.pem

mysqlx-ssl-ca=/usr/local/var/mysql/ca.pem
mysqlx-ssl-cert=/usr/local/var/mysql/server-cert.pem
mysqlx-ssl-key=/usr/local/var/mysql/server-key.pem

foo$ mysql.server restart
Shutting down MySQL
... SUCCESS!
Starting MySQL
. SUCCESS!

foo$ mysql -u root -p --ssl-ca=/usr/local/var/mysql/ca.pem
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.16 Homebrew

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

You are enforcing ssl conection via unix socket. Please consider
switching ssl off as it does not make connection via unix socket
any more secure.
mysql> \s
--------------
mysql  Ver 14.14 Distrib 5.7.16, for osx10.10 (x86_64) using  EditLine wrapper

Connection id:      3
Current database:
Current user:       root@localhost
SSL:            Cipher in use is DHE-RSA-AES128-GCM-SHA256
Current pager:      stdout
Using outfile:      ''
Using delimiter:    ;
Server version:     5.7.16 Homebrew
Protocol version:   10
Connection:     Localhost via UNIX socket
Server characterset:    utf8
Db     characterset:    utf8
Client characterset:    utf8
Conn.  characterset:    utf8
UNIX socket:        /tmp/mysql.sock
Uptime:         25 sec

Threads: 1  Questions: 7  Slow queries: 0  Opens: 105  Flush tables: 1  Open tables: 98  Queries per second avg: 0.280
--------------

mysql> show status like 'ssl_cipher';
+---------------+---------------------------+
| Variable_name | Value                     |
+---------------+---------------------------+
| Ssl_cipher    | DHE-RSA-AES128-GCM-SHA256 |
+---------------+---------------------------+
1 row in set (0.00 sec)

mysql> \q
Bye

foo$ mysqlsh -u root --port=33060 --ssl-ca=/usr/local/var/mysql/ca.pem
Creating a Session to 'root@localhost:33060?sslCa=/usr/local/var/mysql/ca.pem'
Enter password:
Node Session successfully established. No default schema selected.
Welcome to MySQL Shell 1.0.9

Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type '\help', '\h' or '\?' for help, type '\quit' or '\q' to exit.

Currently in JavaScript mode. Use \sql to switch to SQL mode and execute queries.
mysql-js> \sql
Switching to SQL mode... Commands end with ;
mysql-sql> \s
MySQL Shell Version 1.0.9

Session type:                 Node
Server type:                  mysql
Connection Id:                1
Default schema:
Current schema:
Current user:                 root@localhost
SSL:                          Not in use.
Server version:               Homebrew
Server characterset:          utf8
Schema characterset:          utf8
Client characterset:          utf8mb4
Conn. characterset:           utf8mb4
mysql-sql> show status like 'ssl_cipher';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Ssl_cipher    |       |
+---------------+-------+
1 row in set (0.00 sec)
mysql-sql> show variables like '%ssl%';
+--------------------+--------------------------------------+
| Variable_name      | Value                                |
+--------------------+--------------------------------------+
| have_openssl       | YES                                  |
| have_ssl           | YES                                  |
| mysqlx_ssl_ca      | /usr/local/var/mysql/ca.pem          |
| mysqlx_ssl_capath  |                                      |
| mysqlx_ssl_cert    | /usr/local/var/mysql/server-cert.pem |
| mysqlx_ssl_cipher  |                                      |
| mysqlx_ssl_crl     |                                      |
| mysqlx_ssl_crlpath |                                      |
| mysqlx_ssl_key     | /usr/local/var/mysql/server-key.pem  |
| ssl_ca             | /usr/local/var/mysql/ca.pem          |
| ssl_capath         |                                      |
| ssl_cert           | /usr/local/var/mysql/server-cert.pem |
| ssl_cipher         |                                      |
| ssl_crl            |                                      |
| ssl_crlpath        |                                      |
| ssl_key            | /usr/local/var/mysql/server-key.pem  |
+--------------------+--------------------------------------+
16 rows in set (0.01 sec)
mysql-sql>

Int * Doubleは不可

 > let a1 = 2 :: Int
 > let a2 = 3 :: Int
 > a1 * a2
6
 > let b1 = 2 :: Double
 > let b2 = 3 :: Double
 > b1 * b2
6.0
 > a1 * b2

<interactive>:1387:6: error:
    • Couldn't match expected type ‘Int’ with actual type ‘Double’
    • In the second argument of ‘(*)’, namely ‘b2’
      In the expression: a1 * b2
      In an equation for ‘it’: it = a1 * b2
 > a2 * b1

<interactive>:1388:6: error:
    • Couldn't match expected type ‘Int’ with actual type ‘Double’
    • In the second argument of ‘(*)’, namely ‘b1’
      In the expression: a2 * b1
      In an equation for ‘it’: it = a2 * b1
 >

JavaとHaskellのパースの違い

関数のパラメータ部分の解析を考えてみます。例えば、foo(1, 3, 4);`(1, 3, 4)の部分をパースすることを試してみます。

仕様としては、

  • 先頭にカッコ開き
  • 末尾にカッコ閉じ
  • 間に、カンマ区切りの数値

があるとします。

Javaの場合ですが、com.mysql.cj.xdevapi.ExprParserから引用してみました。whileループを使って、間に情報がない場合を場合分けしています。

List<Expr> parenExprList() {
     List<Expr> exprs = new ArrayList<>();
     consumeToken(TokenType.LPAREN);
     if (!currentTokenTypeEquals(TokenType.RPAREN)) {
         exprs.add(expr());
         while (currentTokenTypeEquals(TokenType.COMMA)) {
             consumeToken(TokenType.COMMA);
             exprs.add(expr());
         }
     }
     consumeToken(TokenType.RPAREN);
     return exprs;
}

Haskellの場合ですが、Attoparsecライブラリを使ったコードになります。上で言葉で書いた仕様に近いコードになります。

parenExprList :: Parser [PEx.Expr]     
parenExprList = do
  char '('
  x <- sepBy xParse $ char ','
  char ')'
  return x

調べてないですが、Javaでもライブラリを使えばHaskellと似た様に書けるのかもしれません。