How to perform integration testing in Go?
2020-09-29
Integration testing can be triggered by using Drone downstream plugin:
steps:
- name: trigger
  image: plugins/downstream:linux-amd64
  settings:
    params:
    - COMMIT_BRANCH=${DRONE_COMMIT_BRANCH}
    repositories:
    - repo/integration-test@${DRONE_COMMIT_BRANCH}
    server: https://drone.example.com
    token:
      from_secret: drone_token
It can be separated with unit tests by using build tags:
// +build integration
package webserver_test
Then we can write code to perform integration test as usual.
Duc Ba church
2020-07-28
Duc Ba church, Saigon.
Bị theo dõi (Permanent Record) - Edward Snowden
2020-07-15
- 6 tuổi: vặn đồng hồ chậm lại để chơi cho đã
 - 7 tuổi: tháo tung con máy Nintendo ra vì đang chơi Super Mario thì bị hỏng
 - 7 tuổi rưỡi: chép những dòng code “Hello world” đầu tiên trong một lần được đến công ty ba chơi
 - 12 tuổi: làm quen với máy tính trên chiếc Compaq Presario 425 (Intel 486, ổ cứng 200MB)
 - 13 tuổi: hack website của Phòng thí nghiệm Quốc gia Los Alamos (sau đó thì được cảm ơn và hẹn liên lạc lại khi nào 18 tuổi)
 
Save draft mail in Zimbra web client using ChromeDP
2020-07-03
As an engineer, I want to automate everything as much as possible. This CLI tool is created to save a draft mail in Zimbra web client.
Read config file:
func initConfig() {
	if cfgFile != "" {
		// Use config file from the flag.
		viper.SetConfigFile(cfgFile)
	} else {
		// Find home directory.
		home, err := homedir.Dir()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		// Search config in home directory with name ".zwc" (without extension).
		viper.AddConfigPath(home)
		viper.SetConfigName(".zwc")
	}
	viper.AutomaticEnv() // read in environment variables that match
	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err != nil {
		log.Fatal(err)
	}
	fmt.Println("Using config file:", viper.ConfigFileUsed())
}
        
        
        
        How to trigger build steps based on modified directory?
2020-06-26
Using monorepo with multiple micro services, every single commit will trigger a full lint/test/build/publish for every service. What can I do to limit the scope?
To do that, we can use git diff to show changes between commits:
  if [[ -n "${DRONE_PULL_REQUEST}" ]]; then
    most_recent_before="origin/${DRONE_TARGET_BRANCH}"
  elif [[ "${DRONE_BUILD_EVENT}" = "push" && ("${DRONE_COMMIT_BRANCH}" = "master" || "${DRONE_COMMIT_BRANCH}" = "release-"*) ]]; then
    if [[ "${DRONE_COMMIT_BEFORE}" = "$zero" ]]; then
      exit 0
    else
      most_recent_before="${DRONE_COMMIT_BEFORE}"
    fi
  fi
  modified_files=$(git --no-pager diff --name-only "${DRONE_COMMIT_SHA}".."${most_recent_before}");
        
        
        
        Hanoi tour
2020-05-16
The big church, Hanoi.
Hà Nội Tour (nửa ngày, 0 đêm):
- 6h30: các bạn được đánh thức bởi tiếng nhạc du dương: https://www.youtube.com/watch?v=QMEt8_7uBhY
 - 6h35: di chuyển bằng xe “căng hải” từ phòng ngủ ra William C.
 - 6h45: trang phục tự chọn
 - 7h: lúc này “xe ôm” đã đứng ở dưới để sẵn sàng phục vụ.
 - 7h30: các bạn đang có mặt ở Phan Đình Phùng, một trong những con đường đẹp nhất HN. Tại đây, các bạn thoải mái chụp hình, ngắm lá vàng trong ánh nắng đầu hè dễ chịu.
 
Drone build is not triggered after pushing code to Gitea?
2020-05-06
I pushed code to Gitea and nothing happens in Drone. Why?
But if I go to Settings -> Webhooks, then click “Test Delivery” -> build pipeline will be executed. Why?
First, look at the “Recent Deliveries” to see if a webhook is triggerd here when you pushing code. In my case, it’s not. So, looks like the problem is on Gitea side.
By pay close attention to the git output when pushing:
Counting objects: 4, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 2.02 KiB | 2.02 MiB/s, done.
Total 4 (delta 2), reused 0 (delta 0)
hint: The 'hooks/pre-receive' hook was ignored because it's not set as executable.
hint: You can disable this warning with `git config advice.ignoredHook false`.
hint: The 'hooks/update' hook was ignored because it's not set as executable.
hint: You can disable this warning with `git config advice.ignoredHook false`.
hint: The 'hooks/post-receive' hook was ignored because it's not set as executable.
hint: You can disable this warning with `git config advice.ignoredHook false`.
To gitea.pi:quanta/blog.git
 + d29f63d...47e9ed3 master -> master (forced update)
        
        
        
        How a gRPC message uses length-prefixed framing?
2020-05-06
Once we have the encoded data to send to the other end, we need to package the data in a way that other end can easily extract the information. gRPC uses a message framing technique called length-prefixed framing.
Filter gRPC messages:
$ tshark -r grpc.pcapng -Y 'grpc'
Find out a stream: DATA:
216 923.033355    127.0.0.1 → 127.0.0.1    GRPC 108 DATA[1] (GRPC) (PROTOBUF)
and show the packet details:
tshark -r grpc.pcapng -Y "frame.number == 216" -V
        
        
        
        How to show all HTTP2 headers using tshark?
2020-05-05
After sniffing with tcpdump, how can I show all HTTP2 header using tshark?
First, find the frame number based on method:
$ tshark -r grpc.pcapng -Y 'http2.headers.path contains "getBook"'
214 923.033174    127.0.0.1 → 127.0.0.1    HTTP2 150 HEADERS[1]: POST /book.BookInfo/getBook
and then show the packet details:
tshark -r grpc.pcapng -Y "frame.number == 214" -V
HyperText Transfer Protocol 2
    Stream: HEADERS, Stream ID: 1, Length 85, POST /book.BookInfo/getBook
        Length: 85
        Type: HEADERS (1)
        Flags: 0x04
            .... ...0 = End Stream: False
            .... .1.. = End Headers: True
            .... 0... = Padded: False
            ..0. .... = Priority: False
            00.0 ..0. = Unused: 0x00
        0... .... .... .... .... .... .... .... = Reserved: 0x0
        .000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
        [Pad Length: 0]
        Header Block Fragment: 8386459162339faaf74e7eb92a94ec4c54dd39faff418b08…
        [Header Length: 216]
        [Header Count: 8]
        Header: :method: POST
            Name Length: 7
            Name: :method
            Value Length: 4
            Value: POST
            :method: POST
            [Unescaped: POST]
            Representation: Indexed Header Field
            Index: 3
        Header: :scheme: http
            Name Length: 7
            Name: :scheme
            Value Length: 4
            Value: http
            :scheme: http
            [Unescaped: http]
            Representation: Indexed Header Field
            Index: 6
        Header: :path: /book.BookInfo/getBook
            Name Length: 5
            Name: :path
            Value Length: 22
            Value: /book.BookInfo/getBook
            :path: /book.BookInfo/getBook
            [Unescaped: /book.BookInfo/getBook]
            Representation: Literal Header Field with Incremental Indexing - Indexed Name
            Index: 5
        Header: :authority: 127.0.0.1:50051
            Name Length: 10
            Name: :authority
            Value Length: 15
            Value: 127.0.0.1:50051
            :authority: 127.0.0.1:50051
            [Unescaped: 127.0.0.1:50051]
            Representation: Literal Header Field with Incremental Indexing - Indexed Name
            Index: 1
        Header: content-type: application/grpc
            Name Length: 12
            Name: content-type
            Value Length: 16
            Value: application/grpc
            content-type: application/grpc
            [Unescaped: application/grpc]
            Representation: Literal Header Field with Incremental Indexing - Indexed Name
            Index: 31
        Header: user-agent: grpc-go/1.24.0
            Name Length: 10
            Name: user-agent
            Value Length: 14
            Value: grpc-go/1.24.0
            user-agent: grpc-go/1.24.0
            [Unescaped: grpc-go/1.24.0]
            Representation: Literal Header Field with Incremental Indexing - Indexed Name
            Index: 58
        Header: te: trailers
            Name Length: 2
            Name: te
            Value Length: 8
            Value: trailers
            [Unescaped: trailers]
            Representation: Literal Header Field with Incremental Indexing - New Name
        Header: grpc-client: evans
            Name Length: 11
            Name: grpc-client
            Value Length: 5
            Value: evans
            [Unescaped: evans]
            Representation: Literal Header Field with Incremental Indexing - New Name
        
        
        
        brew info gets stuck
2020-04-25
I managed my Mac with SaltStack.
For some reasons, it gets stuck when running brew state:
[INFO    ] Executing command '/usr/local/bin/brew info --json=v1 --installed' as user 'quanta' in directory '/Users/quanta'
As usual, whenever you get a problem, let’s enable debug mode to see what happens:
brew info --json=v1 --installed -d
Now I can see that it stucked at drone/drone repo. By just untap this repo, and it’s solved.
          Quan Tong