VSTSでAngularのユニットテスト
はじめに
今回の記事の構成は下記のとおりです。
- AngularCLI : 7.0.3
- Angular : 7.0.1
Azure DevOpsの略し方が未だにつかめていないので
VSTSの名称でお送りいたします。(ADops…?)
今回のゴール
AngularのUnitTestをVSTSで実施し
結果をVSTSのテストレポートで確認するところまでを目指します。
Angularのプロジェクトの作成からテストコードの作成までは割愛します。
ただ、ネット上に転がっている文献では
PhamtomJSを使用しているものが多いのですが
AzureDevOps(VSTS)でHeadlessChromeが使用できるようになっていることもあり
CIテストに必要な工程はだいぶ減っている印象です
VSTSのReporter出力の準備
VSTSのレポート出力用に、JUnitReporterをインストールします。
また、HeadlessChromeでテストを実行するので、Pupetterもインストールします。
npm i karma-junit-reporter --save-dev
npm i puppeteer --save-dev
karmaでHeadlessChromeを使用する設定を追加していきます。
- karma.conf.js
process.env.CHROME_BIN = require('puppeteer').executablePath();
plugins: [ require('karma-jasmine'), require('karma-chrome-launcher'), require('karma-jasmine-html-reporter'), require('karma-coverage-istanbul-reporter'), require('karma-junit-reporter'), // 追加 require('@angular-devkit/build-angular/plugins/karma') ],
browsers: ['Chrome', 'ChromeHeadless'], //ChromeHeadlessを追加
karmaのテストレポートでjunitを使用するよう設定追加します。
- karma.conf.js
reporters: ['progress', 'kjhtml', 'junit'], // 'jUnitを追加' junitReporter: { // 出力ディレクトリ outputDir: require('path').join(__dirname, '../reports'), // 出力ファイル名 outputFile: 'test-results.xml', suite: '', useBrowserName: false },
Angularのテスト\スクリプト作成
CI環境下で実行するため、HeadlessChromeで一回のみテストを実行するコマンドです。
- package.json
"citest": "ng test --watch=false --no-progress --browsers=ChromeHeadless",
VSTSのCIパイプラインを構築
VSTSでAngularのテストを行うよう、パイプラインを構築していきます。
1.Angular-cliをインストール
ng
コマンドを使用するために@angular/cliをインストールしておきます。
2.npm install を実行
3.組んだCI用のテストを実行する
4.テストが失敗していた場合はレポートを出力する
5.テストが成功していた場合はビルドする
テストで失敗した場合
AngularのTypeScript側で失敗したエラーが
VSTSのレポートから確認できるようになりました。
最後に
少し前まではHeadlessChromeが使えなかったので
PhamtomJSをインストールしたり、設定を追加していたりしたのですが
だいぶ楽にCIの自動テストの構成を作ることができるようになりました。
ただ、npm installをしている関係で、一回のサイクルに5分位かかってしまうので
ビルド時間に制限のあるPrivateリポジトリでのCIについては
乱発しないように注意が必要かもしれません。
Azure WebAppsのHybridConnectionでドハマりしたとき試したこと
Azure WebAppsのHybridConnectionとは、Azure上のVPNなどの閉域網を構成しなくても
社内閉域網サーバー内のデータにアクセスできるツールです。
エンプラ系の課題にリーチしそうですね。
こと、Cloud移行したいんだけど一気には無理・・・なんて要求に対応しやすいです。
WepAppsとオンプレサーバーがつながらない
HybridConnectionはハイブリッド接続マネージャーという
クライアントソフトウェアを介して通信が行われるのですが
基本的にはインストールして、接続するエンドポイントを指定するだけの簡単なものです。
詳細は 過去記事をどうぞ。
しかし、ある環境で試したところ、接続できずに四苦八苦しました。
そのときに試したり確認した色々なことを書いていこうと思います。
0.まずはOSの確認を
HybridConnectionはWebSocketを使用して通信を行っているため
WindowsServerであれば2012以降からしか対応していません。
1.接続設定の確認
HybridConncetionの設定の際に、PCの名称を指定するフィールドがあります。
ここの部分で名称を間違えたり、IPアドレスを指定したりすると繋がりません。
正しい設定になっているかどうか確認します。
2.ファイアウォールの確認
HybridConnectionは送信ポート443を使用して通信します。
ハイブリッド接続マネージャでエンドポイントを設定する際は
受信・送信ともにポート443を開放していないと設定できないですが
設定後は、送信ポートだけの開放でも問題なく動作するようです。
OSのファイアウォールで送信ポート443がブロックされているようであれば
開放してあげましょう。
※もちろん443を潰すということはセキュリティ的に重要なPCの可能性が高いので事前確認は忘れずに!
3.サービスが可動しているか確認
前述の通り、HybridConnectionはハイブリッド接続マネージャを介して通信が行われるので
常駐プロセスが立っているはずです。これが停止されていないか確認します。
4.インターネット接続の確認
それでもつながらない場合、そもそもインターネットにつながっている状態か確認します。
状況により下記の通り対応が分岐されます。
4.1 つながらない
ルーターの設定でブロックされている可能性があるので、ルーターの設定を確認します。
4.2 つながる
Proxyサーバーを介して通信が行われている可能性があるので確認します。
4.2.1 Proxy設定を確認
インターネットオプションから、Proxyを介した接続設定となっているか確認を行います。
4.2.2 ハイブリッド接続の設定を変更
Proxyを介して通信を行う設定となっていた場合
ハイブリッド接続マネージャーも、Proxyを介して通信をするよう変更します。
ハイブリッド接続マネージャーの実行ファイルと、同じディレクトリにある
Microsoft.HybridConnectionManager.Listener.exe.config
ファイルの中身を変更します。
設定に下記内容を付け加えます。
<system.net> <defaultProxy> <proxy usesystemdefault="true" proxyaddress="http://hogehoge.proxyserver:1111" /> </defaultProxy> </system.net>
proxyaddress
には先程インターネットオプションで確認したProxy設定を記述します。
自分はひとまずこれで接続することができました。
最後に
HybridConnectionは、大雑把に言ってしまえばSSLでデータをやり取りしているだけなので
ハイブリッド接続マネージャーを入れたサーバーで、インターネットにつながるのであれば
netstat
とか Test-NetConnection
を使用して
通常のネットブラウズで使用されている経路やポートを抑えるのが、解決への早道となりそうです。
AngularとAzureAD認証でログイン機構を簡単に実現したい
最初に
今回使用した環境は下記の通りです。
- @angular/cli : 6.0.8
- @angular : 6.0.7
AzureAD認証を支援するJSライブラリ
AzureActiveDirectory認証を支援するJSライブラリとして
MicrosoftからADALというJSライブラリが提供されています。
マルチテナント型のAzureADB2CはMSALと呼ばれるライブラリを使用するようです。
ADALのAngularラッパーを取得
Angular使いなので、Angularでadal.jsを使おうと思います。
adal.js自体はnpmでパッケージ提供されていないようです。。。
Angularで使用できるラッパーは提供されているようなのでそいつを使用していきます。
npm install adal-angular4 --save
Angular4と書かれていますが6も対応されています。
Angular6対応版もありますが、Deprecateして4に吸収されているようです。
(名前、ngx~みたいな形のほうがわかりやすいですよね…)
ServiceをImportしてProvide
まずはInjection宣言されている、AdalSeviceを app.module.ts
でProvideします。
import { AdalService } from 'adal-angular4'; ・・・ providers: [ AdalService ],
ADの情報を設定
AdalService.init()
に使用するADの情報を食わせる必要があります。
Sampleで指定されているのではTenantとClientIDです。
TenantはADで使用されているドメイン。
ClientIDはADに登録されたアプリケーションのApplicationIDを指定します。
handleWindowCallbackでログイン状態の収集
先程ProvideしたAdalServiceを介して認証情報のやり取りを行います。
サービス内の handleWindowCallback()
を使用し
サインインされているか~ですとか、Tokenの情報~ですとか
そういった情報が収集されているようです。
ログインされているかの情報は
this._adalService.userInfo.authenticated
で確認できるので
ログインされているかを確認し
ログインされていないようであればログインするようにしてみます。
constructor( private _adalService: AdalService, ) { } ・・・ ngOnInit() { this._adalService.handleWindowCallback(); if (!this._adalService.userInfo.authenticated) { this._adalService.login(); } }
このようにしておくと、Componentの初期化と同時に
AD未ログイン状態だった場合は
AzureActiveDirectoryの認証画面にリダイレクトされます。
AdalGuardでComponentの遷移Guard
AdalGuardは、Angularの CanActivate
と
上記の userInfo.authenticated
を使用して
AD未ログインユーザーのRoutingの制限を行うSampleという認識です。
adal-angular4/adal.guard.ts at master · benbaran/adal-angular4 · GitHub
認証されていないユーザーへの移動制限をかけたい場合は
routerの設定のときにAdalGuardを指定するだけでOKといった塩梅です。
ここで認証されていない場合は強制的にリダイレクトかけたりなんだりしたいと思うので
基本的にAdalGuardをそのまま使用することはないかなぁ?と思っています。
今回はLoginComponentからDashboardComponentへの遷移の設定を作ってみます。
const routes: Routes = [ { path: 'login', component: LoginComponent }, { path: 'dashboard', component: DashBoardComponent, canActivate: [AdalGuard] }, { path: '', component: LoginComponent }, ];
今回はAdalGuardをそのまま使用します。
認証がすでに済んでいるものはURL指定で直接遷移できていますが
認証が済んでいないほうはRouterで遷移ができずに
何も表示されていない状態になっています。
AD認証のAuthがかかったASP.net WebAPIへのアクセス
adal-angular4が提供する AdalInterceptor
が
AngularのHTTP_INTERCEPTORを使用して、ヘッダに認証情報を付与します。
adal-angular4/adal.interceptor.ts at master · benbaran/adal-angular4 · GitHub
なので、app.module.ts
でInterceptorのInjectionを行えばいい感じです。
providers: [ AdalService, { provide: HTTP_INTERCEPTORS, useClass: AdalInterceptor, multi: true } ],
WebAPIを作る
WebAPIはASP.net CoreでAD認証付きのAPIがテンプレートから作れるので
それでサクッと作ってしまいます。
F5実行して動作を見てみます。
アクセスするAPIはデフォルトで存在する /api/values
のGetにアクセスしてみます。
まずは、RestletClientから、Token情報を付与しない状態でアクセスしてみます。
401エラーが返却されました。認証は問題なく動作しているようです。
AdalInterceptorを通してからアクセスした場合を見てみます。
横着してConsole出力で済ませています。
Networkからも、HeaderのAuthorizationにTokenが使用されているのが確認できます。
先程失敗したRestletClientで、使用されたTokenを使ってみます。
通りました。正しいTokenのようです。
まとめ
JSでのActiveDirectory認証はADALを使用します。
今回はAngularを使用しましたがVue用等
各Frameworkのものも用意されているようです。
ログイン画面やアカウント管理は非常に重要で気も使う部分です。
簡易な要望でADを使用している人や会社が対象であれば
AD認証で認証ロジックを丸投げしてしまうのもありですよね。
Desktop PWAs 体験してみた
最近話題になったこと
最近、WindowsのDesktopでPWAが動くぜー!と話題になっていました。
英語力が低いので誤解しているかもしれないですが
これはストアアプリの内部としてPWAも使えるようになりますよー
ってアナウンスなのかなとも思っていました。
普通に動かす分にはもう出来るっぽい
ちょっと調べてみると
上記の記事の内容からすると、もうPWAのWebAppを
アプリケーションとしてデスクトップに配置することは可能になっているようです。
というわけで試してみました。
かなり簡単に試すことができました。
Chromeの設定
ChromeのVersionは 64.0.3282.186(Official Build) (64 ビット)
で試しました。
まずは chrome://flags/
で現在試験運用中のPWAs Desktopを使えるようにします。
Chromeの再起動が要求されるのでChromeの再起動を行います。
PWAのサイトを開く
PWA対応のサイトは下記のPWA Rocksから探せますので、お好きなサイトを立ち上げます。
今回は、MobileTwitterを使ってみます
https://mobile.twitter.com/home
デスクトップに追加する
メニューからデスクトップに追加できるようになっているのでデスクトップに追加します。
デスクトップにChromeアイコンではなく、アプリケーションのアイコンっぽいものが生えてきました!
恥ずかしいタイポは気にしないでください!
開いてみると、Chromeのブラウザではなく
アプリのウィンドウっぽい画面でTwitterが立ち上がりました!
最後に
PWAサイトをアプリケーションのように使うという
モバイルで出来ていたことがWindowsでも実現できるようになりました。
PWAアプリケーションのすそ野がまた一つ広がりましたね!
お手軽に試せるので、皆様もぜひ試してみてください!
Reactive FormsでオリジナルのComponentを使用する
初めに
今回の記事は、下記構成でお送りします。
- Angular: 5.1.1
- AngularCli: 1.6.1
Reactive FormsでOriginalのComponentを使いたい
業務系のWebApp作るお仕事してるとReactive Formsを多用します。
Validatorのエラーチェック部分を楽に作れるのが気に入ってます。
ただ、DBから引っ張ってきたマスタListのSelectBoxとか
多くのところで使用するようなコントロールは共通化したいところです。
そこで、Component部品をReactive Formsで使用できないか試してみました。
まずは単純なReactive Forms
ログイン画面っぽいもの想定して、単純なReactive Formsの画面を作ってみます。
<form [formGroup]="inputForm"> <input [formControlName]="USER_ID_KEYWORD" placeholder="ユーザーID" /> <label style="color:red" *ngIf="formErrors[USER_ID_KEYWORD]">{{formErrors[USER_ID_KEYWORD]}}</label> <br/> <input [formControlName]="PASSWORD_KEYWORD" placeholder="パスワード" /> <label style="color:red" *ngIf="formErrors[PASSWORD_KEYWORD]">{{formErrors[PASSWORD_KEYWORD]}}</label> </form>
ユーザーIDコントロールだけ切り出し、別Componentに
- ユーザーIDコントロールは
app-user-id-text
という名前で作成しました
<form [formGroup]="inputForm"> <app-user-id-text [formControlName]="USER_ID_KEYWORD"></app-user-id-text> <label style="color:red" *ngIf="formErrors[USER_ID_KEYWORD]">{{formErrors[USER_ID_KEYWORD]}}</label> <br/> <input [formControlName]="PASSWORD_KEYWORD" placeholder="パスワード" /> <label style="color:red" *ngIf="formErrors[PASSWORD_KEYWORD]">{{formErrors[PASSWORD_KEYWORD]}}</label> </form>
まずは、単純に、新しく作成したComponentに
ユーザーIDで使用してたFormControlNameを使用してみます。
エラー
ですよねー。ってことで修正します。
Reactive Formsの作り方を思い出す
Reactive Formsは、ComponentのInit時に、下記のように作成したはずです。
buildForm() { this.inputForm = this.fb.group(this.formSetting); this.inputForm.valueChanges.subscribe(data => { this.onValueChange(data); }); this.onValueChange(); }
FormのSetting情報を、FormBuilder.groupを使用して
FormGroup
プロパティに突っ込んでいます。
つまり、Componentに対してFormGroupの情報を送ってやれば良いのかもしれません。
子ComponentにFormGroupのプロパティを生やす
@Input() fg: FormGroup
のプロパティを生やしました。
export class UserIdTextComponent implements OnInit { @Input() fg: FormGroup; ... }
Componentを使用する際に
<app-user-id-text [fg]="hogeForm"> ...
みたいな感じで使用します。
結果
通りました。
入力内容が@Input
のFormGroupを通して、親Componentに伝播し
また、オリジナルComponentのValidationエラーが
親Componentのエラーメッセージプロパティに格納されました。
最後に
今回作成したコードは、下記にあげてあります。
煮るなり焼くなりお好きにしてくださいませ。
…Angular v2時代に作った勉強用のリポジトリそろそろ名前変えないとなぁ…
Xamarin.AndroidでNfc機能の技術検証した話
この記事は
[初心者さん・学生さん大歓迎!] Xamarin その1 Advent Calendar 2017
13日目の記事となります。Advent Calendar初挑戦です。よろしくお願いします!
初めに
Xamarin.Formsはずいぶん前からちょこちょこ触ってましたが
本業はWebの方のお仕事中心で、正直まだまだ初心者の域を脱していません。
ですが、最近、Nativeの技術検証をする機会がありましたので
Xamarinで色々やってみた話です。
Xamarin.Androidの話になります。iOSまでは手を出せませんでした。
今回の記事はコードなしで感想中心となります。
コードは後述するGitHubに上げてますので煮るなり焼くなり致してくださいませ。
技術検証したこと
AndroidのNfcを使用し、Suicaとかから履歴情報を引き抜く
まずはkotlin
AndroidにおけるSuicaから履歴を抜く方法については検索してすぐ見つかりました。
特に参考になったのは下記のページです。
が、JavaやKotlinのコードをC#に素直に変換できるか不安がありました。
なので、まずはkotlinで実装し
どのように動作するのか確認しながらC#に落とし込む手法を取りました。
基本は上記のページを参考に、kotlinの実装と動作を確認しつつ写経しました。
GitHub - Takas0522/FelicaCardReaderSample: FelicaCardReaderをKotlinで作ってみたSample
kotlinで出来上がったのが上記のコードです。
リクエストをByte配列で受け取る方式で、カードの履歴情報を取得します。
Xamarin.Androidに
はまったか?
案外、ハマる部分は少なく、素直に移行できたかと思います。
と、いうのも、NFCのやりとりで使用するNfcFクラスといったクラスの使い方は
ほぼ、kotlinのときと同様の使い方ができたので
その部分については迷うことは少なかったです。
(「Byte配列作る→投げる→Byte配列もらう」だけなので特例とは思いますが…)
なので、Xamarin特有(?)のR→Resourceとか、Intent周り等
基本的な、且つ、kotlinやJavaの記法から変わってる部分で少しハマったりしました。
最終的に、そういった基本的な部分で困ったら
Xamarin公式のドキュメントからサンプルソース落として
基本動作を抑える解決方法に落ち着きました。
kotlinで先に書いてみた恩恵
今回は特殊なケースかもしれませんが
Xamarinでうまく動作できないとき、kotlinで動作させてみて
Byte配列の変数の状態等をチェックすることもできたので
先にkotlinでコード書いてみたのが非常に活かせることができました。
Xamarinでうまく動かないときは
同様な動作をkotlin等のNativeコードで動かしてみると
色々気づきがあるかもしれません。
kotlinの書き換えが地味に多い
kotlinはオブジェクト操作周りが充実している印象で
その周りのC#の書き換えが地味に多かったです。
(Byte配列いじくることばっかやってたのでだいぶ偏った印象かも。。)
.netから見たkotlinの良さは、@amay077 さんの記事が参考になるかと思います。
自分は、Byte配列のここからここまでコピーする。みたいな CopyOfRange
とか
Byte配列の Write
ファンクションでByte配列に値を格納していくー。みたいな
Kotlin標準の機能の拡張を我慢できずに作ったりはしました。
ほかの言語に触れることでよさげな機能を発見して
C#の実装に取り込むといったことができるのも
Nativeコードに触れる良さかな。と思いました。
まとめ
勉強目的ならNativeコードから書いたほうが格段に良い
NativeコードからのC#への移行はあんがいあっさり行えた
- ただし、NativeAPIをほとんど使用していない。
- NativeAPIを多用し始めるとまた別の落とし穴が見えてくるはず
基本的な部分はXamarin公式ドキュメントのサンプルで粗方洗える
さいごに
今回作成したXamarin.Androidのコードは下記になります。
GitHub - Takas0522/FelicaCardReaderSampleXamarin
明日のAdventCalendarは @masanori-_-msl さんです。
よろしくお願いします!
AzureのVMと自社サーバーをVPNでつなげて(かんたんな)Deployをしてみる
実験的要素モリモリでございます。
ビルドサーバーのVirtualMachineはAzure上にある。
でも、検証環境は自社の閉域ネットワーク内のどこそこにある。といった場合に。
(きわめてレアだとは思いますが!)
ちなみに使用するGatewayとか高めのお値段なので
自前の閉域環境内にサーバ用意できるのであればそちらのほうが良いと思います。
どちらかというとIaaSの環境をVPNで自社VPNに接続する手法がメインとなりますし
そちら単独のほうがよくあるパターンだとは思います。
CIは「いけんじゃね?」的なフィーリングの実験です。
下図な感じの構成で今回作ってみます。
参考資料
Point To Site
VSTSとJenkinsをつなげるときに参考
Jenkins
Azure準備
まずはAzure上の環境を構築します。
Azure上で作成したVM仮想環境から、閉域環境内(社内等)にVPN接続できる状態まで持っていきます
[Point To Site]という手法を使用します。
Point To Site構成の作成
仮想ネットワークのアドレス空間の追加
仮想ネットワークサブネットの作成
仮想ネットワークゲートウェイの作成
先ほど設定した仮想ネットワークをターゲットにゲートウェイを作成します。
自己証明書を作成
- WindowsServer2016以降の場合
- PowerShellで[New-SelfSignedCertificate]実行が鉄板です。
MakeCer.exeを使用したい場合
- Azureで作成したWindowsServerにはWindowsSDKが入っていない
別途インストールしてやる必要があります。
できあがったルート証明書とクライアント証明書のCerとPfxをエクスポートします。
- pfxはbase64形式でエクスポートします。
ゲートウェイの設定
- アドレスプールとルート証明書を設定します。
- アドレスプールはこれまで指定してきたものと別のIPアドレス空間を指定します
- ([10.0.0.0/24]とか指定したら[10.1.0.0/24]みたいな感じですかね?)
- 上記で作成した証明書をエディタかなにかで開き内部コードを編集します。
- 改行コードが入っているので、改行部分をつぶします。
VirtualGatewayのセットアップ
接続設定の変更
※この作業が必要かどうかはちょっと微妙ですが
- AzureVMクからライアント環境への参照はそのままでは行えないです。
- インターネットオプション/Chromeの[設定]>[詳細詳細]>[プロキシ設定を開く]から[接続]の設定
- 先ほど作成したVPNクライアントを選択し[設定]
- 「設定を自動的に検出する」
接続の確認
作成したVPN内のIPアドレスは、コマンドプロンプトの[ipconfig]で確認することができます。
特に設定していないため、下図のIPアドレスはVPNの接続の度変わります。
以降の図等でのIPアドレスの表記は、下図のものと異なる場合があります。
ネットワーク設定でリモート接続やファイル共有を
プライベートネットワーク内でできるようにしたうえで
AzureのVM上からVPN内の端末にアクセスできるか試してみます、
問題なく接続できるようです。
VSTSの設定
アカウント設定
Jenkinsからソースを抜けるように、VSTSの[authentication credentials]を設定します。
ユーザー名の[Security]>[authentication credentials]から設定可能です。
Jenkinsの設定
インストール
公式のドキュメントどおりにインストールします。
ビルド環境準備
以降必要があれば…
- PowerShellプラグイン
- コマンドプロンプトじゃ足りないとき(UNCパスに接続する時とか…)
- MSBuildプラグイン
- .NetFramework
- .NetFrameworkのビルド用
- .NetCore
- .NetCoreのビルド用
- Node.js
- Npmコマンド実行したいとき
CI環境の設定
ひとまず今回はてっとりばやく、VSTSから取得したAngularをBuildした成果物を
下記の感じでPowerShellスクリプトを実行します。
- npm i - Javascriptパッケージインストール
- ng build - JavascriptBuild
- Copy-Item - 成果物の移動
回してみる
AzureのVMから、Jenkinsを使ってVPN内のパスにDeployできるようになりました。