diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..4925ac6a86 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,44 @@ +name: ci + +on: + pull_request: + branches: [main] + +jobs: + tests: + name: Tests + runs-on: ubuntu-latest + + steps: + - name: Check out code + uses: actions/checkout@v6 + - name: Set up Go + uses: actions/setup-go@v6 + with: + go-version: "1.26.0" + - name: run unit test + run: go test ./... -cover + - name: install gosec + run: go install github.com/securego/gosec/v2/cmd/gosec@latest + - name: run test with gosec + run: gosec ./... + + style: + name: Style + runs-on: ubuntu-latest + + steps: + - name: Check out code + uses: actions/checkout@v6 + - name: Set up Go + uses: actions/setup-go@v6 + with: + go-version: "1.26.0" + - name: Code formatting cek + run: test -z $(go fmt ./...) + - name: Install Static Check + run: go install honnef.co/go/tools/cmd/staticcheck@latest + - name: linting with Static Check + run: staticcheck ./... + + diff --git a/README.md b/README.md index c2bec0368b..01c521a6bd 100644 --- a/README.md +++ b/README.md @@ -21,3 +21,7 @@ go build -o notely && ./notely *This starts the server in non-database mode.* It will serve a simple webpage at `http://localhost:8080`. You do *not* need to set up a database or any interactivity on the webpage yet. Instructions for that will come later in the course! + +Pikron's version of Boot.dev's Notely app. + +![alt text goes here](https://github.com/fikri220/learn-cicd-starter/actions/workflows/ci.yml/badge.svg) \ No newline at end of file diff --git a/internal/auth/get_api_key_test.go b/internal/auth/get_api_key_test.go new file mode 100644 index 0000000000..90dc8c1c74 --- /dev/null +++ b/internal/auth/get_api_key_test.go @@ -0,0 +1,75 @@ +package auth + +import ( + "errors" + "net/http" + "testing" +) + +func TestGetAPIKey(t *testing.T) { + + tests := []struct { + name string + header string + expectedKey string + expectedErr error + }{ + { + name: "valid api key", + header: "ApiKey abc123", + expectedKey: "abc123", + expectedErr: nil, + }, + { + name: "missing authorization header", + header: "", + expectedKey: "", + expectedErr: ErrNoAuthHeaderIncluded, + }, + { + name: "wrong authorization scheme", + header: "Bearer abc123", + expectedKey: "", + expectedErr: errors.New("malformed authorization header"), + }, + { + name: "missing api key", + header: "ApiKey", + expectedKey: "", + expectedErr: errors.New("malformed authorization header"), + }, + { + // Sesuai implementasi GetAPIKey saat ini (strings.Split), + // "ApiKey " dianggap valid dan menghasilkan key kosong. + name: "empty api key", + header: "ApiKey ", + expectedKey: "", + expectedErr: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + headers := http.Header{} + if tt.header != "" { + headers.Set("Authorization", tt.header) + } + key, err := GetAPIKey(headers) + if key != tt.expectedKey { + t.Errorf("expected key %q, got %q", tt.expectedKey, key) + } + if tt.expectedErr == nil { + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + return + } + if err == nil { + t.Fatalf("expected error %v, got nil", tt.expectedErr) + } + if err.Error() != tt.expectedErr.Error() { + t.Errorf("expected error %q, got %q", tt.expectedErr.Error(), err.Error()) + } + }) + } + +} diff --git a/json.go b/json.go index 1e6e7985e1..30eae27359 100644 --- a/json.go +++ b/json.go @@ -30,5 +30,7 @@ func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) { return } w.WriteHeader(code) - w.Write(dat) + if _, err := w.Write(dat); err != nil { + log.Printf("failed to write response: %v", err) + } } diff --git a/main.go b/main.go index 19d7366c5f..eb5053ceec 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,7 @@ import ( "log" "net/http" "os" + "time" "github.com/go-chi/chi" "github.com/go-chi/cors" @@ -32,7 +33,7 @@ func main() { port := os.Getenv("PORT") if port == "" { - log.Fatal("PORT environment variable is not set") + log.Fatal("PORT environment variable is not set yet") } apiCfg := apiConfig{} @@ -91,8 +92,9 @@ func main() { srv := &http.Server{ Addr: ":" + port, Handler: router, + ReadHeaderTimeout: 5 * time.Second, } - log.Printf("Serving on port: %s\n", port) log.Fatal(srv.ListenAndServe()) + //trigger testing PR }