How to perform integration testing in Go?
2020-09-29
Integration testing can be triggered by using Drone downstream plugin:
1steps: 2- name: trigger 3 image: plugins/downstream:linux-amd64 4 settings: 5 params: 6 - COMMIT_BRANCH=${DRONE_COMMIT_BRANCH} 7 repositories: 8 - repo/integration-test@${DRONE_COMMIT_BRANCH} 9 server: https://drone.example.com 10 token: 11 from_secret: drone_token
It can be separated with unit tests by using build tags:
1// +build integration 2 3package webserver_test
Then we can write code to perform integration test as usual.
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:
1 if [[ -n "${DRONE_PULL_REQUEST}" ]]; then 2 most_recent_before="origin/${DRONE_TARGET_BRANCH}" 3 elif [[ "${DRONE_BUILD_EVENT}" = "push" && ("${DRONE_COMMIT_BRANCH}" = "master" || "${DRONE_COMMIT_BRANCH}" = "release-"*) ]]; then 4 if [[ "${DRONE_COMMIT_BEFORE}" = "$zero" ]]; then 5 exit 0 6 else 7 most_recent_before="${DRONE_COMMIT_BEFORE}" 8 fi 9 fi 10 modified_files=$(git --no-pager diff --name-only "${DRONE_COMMIT_SHA}".."${most_recent_before}");
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:
1Counting objects: 4, done. 2Delta compression using up to 4 threads. 3Compressing objects: 100% (4/4), done. 4Writing objects: 100% (4/4), 2.02 KiB | 2.02 MiB/s, done. 5Total 4 (delta 2), reused 0 (delta 0) 6hint: The 'hooks/pre-receive' hook was ignored because it's not set as executable. 7hint: You can disable this warning with `git config advice.ignoredHook false`. 8hint: The 'hooks/update' hook was ignored because it's not set as executable. 9hint: You can disable this warning with `git config advice.ignoredHook false`. 10hint: The 'hooks/post-receive' hook was ignored because it's not set as executable. 11hint: You can disable this warning with `git config advice.ignoredHook false`. 12To gitea.pi:quanta/blog.git 13 + 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:
1$ tshark -r grpc.pcapng -Y 'grpc'
Find out a stream: DATA
:
1216 923.033355 127.0.0.1 → 127.0.0.1 GRPC 108 DATA[1] (GRPC) (PROTOBUF)
and show the packet details:
1tshark -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:
1$ tshark -r grpc.pcapng -Y 'http2.headers.path contains "getBook"' 2214 923.033174 127.0.0.1 → 127.0.0.1 HTTP2 150 HEADERS[1]: POST /book.BookInfo/getBook
and then show the packet details:
1tshark -r grpc.pcapng -Y "frame.number == 214" -V 2 3HyperText Transfer Protocol 2 4 Stream: HEADERS, Stream ID: 1, Length 85, POST /book.BookInfo/getBook 5 Length: 85 6 Type: HEADERS (1) 7 Flags: 0x04 8 .... ...0 = End Stream: False 9 .... .1.. = End Headers: True 10 .... 0... = Padded: False 11 ..0. .... = Priority: False 12 00.0 ..0. = Unused: 0x00 13 0... .... .... .... .... .... .... .... = Reserved: 0x0 14 .000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1 15 [Pad Length: 0] 16 Header Block Fragment: 8386459162339faaf74e7eb92a94ec4c54dd39faff418b08… 17 [Header Length: 216] 18 [Header Count: 8] 19 Header: :method: POST 20 Name Length: 7 21 Name: :method 22 Value Length: 4 23 Value: POST 24 :method: POST 25 [Unescaped: POST] 26 Representation: Indexed Header Field 27 Index: 3 28 Header: :scheme: http 29 Name Length: 7 30 Name: :scheme 31 Value Length: 4 32 Value: http 33 :scheme: http 34 [Unescaped: http] 35 Representation: Indexed Header Field 36 Index: 6 37 Header: :path: /book.BookInfo/getBook 38 Name Length: 5 39 Name: :path 40 Value Length: 22 41 Value: /book.BookInfo/getBook 42 :path: /book.BookInfo/getBook 43 [Unescaped: /book.BookInfo/getBook] 44 Representation: Literal Header Field with Incremental Indexing - Indexed Name 45 Index: 5 46 Header: :authority: 127.0.0.1:50051 47 Name Length: 10 48 Name: :authority 49 Value Length: 15 50 Value: 127.0.0.1:50051 51 :authority: 127.0.0.1:50051 52 [Unescaped: 127.0.0.1:50051] 53 Representation: Literal Header Field with Incremental Indexing - Indexed Name 54 Index: 1 55 Header: content-type: application/grpc 56 Name Length: 12 57 Name: content-type 58 Value Length: 16 59 Value: application/grpc 60 content-type: application/grpc 61 [Unescaped: application/grpc] 62 Representation: Literal Header Field with Incremental Indexing - Indexed Name 63 Index: 31 64 Header: user-agent: grpc-go/1.24.0 65 Name Length: 10 66 Name: user-agent 67 Value Length: 14 68 Value: grpc-go/1.24.0 69 user-agent: grpc-go/1.24.0 70 [Unescaped: grpc-go/1.24.0] 71 Representation: Literal Header Field with Incremental Indexing - Indexed Name 72 Index: 58 73 Header: te: trailers 74 Name Length: 2 75 Name: te 76 Value Length: 8 77 Value: trailers 78 [Unescaped: trailers] 79 Representation: Literal Header Field with Incremental Indexing - New Name 80 Header: grpc-client: evans 81 Name Length: 11 82 Name: grpc-client 83 Value Length: 5 84 Value: evans 85 [Unescaped: evans] 86 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:
1[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:
1brew 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.
Why my golang docker container exits immediately (code 127)?
2019-10-30
To trim the binary size, I used LDFLAGS='-w -s'
, pack with upx
, then build from scratch. The thing is when starting, it exited immediately with code 127. Why?
My Dockerfile:
1FROM scratch 2 3WORKDIR /app 4 5COPY build/linux/<binary> . 6 7ENTRYPOINT [ "/app/<binary>" ]
When starting:
10fbce782a9bd quantonganh/<binary>:T276-dockerize "/app/<binary>" 6 seconds ago Exited (127) 4 seconds ago relaxed_thompson
Command-line autocomplete for Go documentation
2019-09-26
Go has a great, well documented standard library. You may find yourself spending a fairly significant chunk of your Go programming time digging in stdlib docs, which is reasonable to expect at least for novice Go coders.
https://eli.thegreenplace.net/2018/command-line-autocomplete-for-go-documentation/
Auto reload your Go webserver with Gulp
2019-09-20
When you developp a webserver with Go, you must compile each time you do an update in your code. Well.. this is redundant. With Gulp you can automatize this task… Indeed, when a go file is modified, a task compile the application in the “bin” folder (“gopath/bin”) then another launch the executable (the webserver).
https://medium.com/@etiennerouzeaud/autoreload-your-go-webserver-with-gulp-ee5e231d133d
1const gulp = require('gulp'), 2 util = require('gulp-util'), 3 notifier = require('node-notifier'), 4 child = require('child_process'), 5 os = require('os'), 6 path = require('path'); 7 8var server = 'null' 9 10function build() { 11 var build = child.spawn('go', ['install']); 12 13 build.stdout.on('data', (data) => { 14 console.log(`stdout: ${data}`); 15 }); 16 17 build.stderr.on('data', (data) => { 18 console.error(`stderr: ${data}`); 19 }); 20 21 return build; 22} 23 24function spawn(done) { 25 if (server && server != 'null') { 26 server.kill(); 27 } 28 29 var path_folder = process.cwd().split(path.sep) 30 var length = path_folder.length 31 var app = path_folder[length - parseInt(1)]; 32 33 if (os.platform() == 'win32') { 34 server = child.spawn(app + '.exe') 35 } else { 36 server = child.spawn(app) 37 } 38 39 server.stdout.on('data', (data) => { 40 console.log(`stdout: ${data}`); 41 }); 42 43 server.stderr.on('data', (data) => { 44 console.log(`stderr: ${data}`); 45 }); 46 47 done(); 48} 49 50const serve = gulp.series(build, spawn) 51function watch(done) { 52 gulp.watch(['*.go', '**/*.go'], serve); 53 done(); 54} 55 56exports.serve = serve 57exports.watch = watch 58exports.default = gulp.parallel(serve, watch)