package httpapi import ( "encoding/csv" "encoding/json" "io" "net/http" "net/http/httptest" "strings" "testing" ) func TestModuleEntriesCSVImportExportIPRanges(t *testing.T) { srv, err := New(Options{ InsecureDev: true, SeedDemo: true, }) if err != nil { t.Fatal(err) } defer srv.Close() tenant, _, modIP, _, _ := srv.Store().DemoIDs() mustSetTestAPIKeys(t, srv, "opkey|"+tenant+"|operator") ts := httptest.NewServer(srv.Handler()) defer ts.Close() client := ts.Client() base := ts.URL reqList, _ := http.NewRequest(http.MethodGet, base+"/v1/communities?limit=10", nil) reqList.Header.Set("Authorization", "Bearer opkey") respList, err := client.Do(reqList) if err != nil { t.Fatal(err) } defer func() { _ = respList.Body.Close() }() if respList.StatusCode != http.StatusOK { b, _ := io.ReadAll(respList.Body) t.Fatalf("communities status %d: %s", respList.StatusCode, b) } var listBody struct { Items []struct { Community string `json:"community"` } `json:"items"` } if err := json.NewDecoder(respList.Body).Decode(&listBody); err != nil { t.Fatal(err) } if len(listBody.Items) == 0 { t.Fatal("expected seeded community") } csvBody := "\"ipRange\",\"community\"\n\"10.254.1.254/32\",\"" + listBody.Items[0].Community + "\"\n\"160.79.104.0/23\",\"" + listBody.Items[0].Community + "\"\n" reqImport, _ := http.NewRequest(http.MethodPost, base+"/v1/modules/"+modIP+"/entries.csv", strings.NewReader(csvBody)) reqImport.Header.Set("Authorization", "Bearer opkey") reqImport.Header.Set("Content-Type", "text/csv") respImport, err := client.Do(reqImport) if err != nil { t.Fatal(err) } defer func() { _ = respImport.Body.Close() }() if respImport.StatusCode != http.StatusOK { b, _ := io.ReadAll(respImport.Body) t.Fatalf("import status %d: %s", respImport.StatusCode, b) } var importBody struct { Imported int `json:"imported"` } if err := json.NewDecoder(respImport.Body).Decode(&importBody); err != nil { t.Fatal(err) } if importBody.Imported != 2 { t.Fatalf("expected imported=2, got %d", importBody.Imported) } reqExport, _ := http.NewRequest(http.MethodGet, base+"/v1/modules/"+modIP+"/entries.csv", nil) reqExport.Header.Set("Authorization", "Bearer opkey") respExport, err := client.Do(reqExport) if err != nil { t.Fatal(err) } defer func() { _ = respExport.Body.Close() }() if respExport.StatusCode != http.StatusOK { b, _ := io.ReadAll(respExport.Body) t.Fatalf("export status %d: %s", respExport.StatusCode, b) } if got := respExport.Header.Get("Content-Type"); !strings.Contains(got, "text/csv") { t.Fatalf("unexpected content-type: %q", got) } raw, err := io.ReadAll(respExport.Body) if err != nil { t.Fatal(err) } records, err := csv.NewReader(strings.NewReader(string(raw))).ReadAll() if err != nil { t.Fatal(err) } if len(records) < 3 { t.Fatalf("expected at least 3 csv rows, got %d", len(records)) } if records[0][0] != "ipRange" || records[0][1] != "community" { t.Fatalf("unexpected header: %#v", records[0]) } }