diff --git a/cmd/fdsn-quake-consumer/sc3ml_test.go b/cmd/fdsn-quake-consumer/sc3ml_test.go index ef27abd..fe937e8 100644 --- a/cmd/fdsn-quake-consumer/sc3ml_test.go +++ b/cmd/fdsn-quake-consumer/sc3ml_test.go @@ -3,6 +3,7 @@ package main import ( "bytes" "database/sql" + "fmt" "io" "os" "reflect" @@ -184,6 +185,75 @@ func TestEventUnmarshalSC12_13(t *testing.T) { } } +// test new event types in SC3ML 0.13 can be unmarshalled +func TestEventUnmarshalSC13_eventTypes(t *testing.T) { + for _, eventType := range []string{ + "volcanic long-period", + "volcanic very-long-period", + "volcanic hybrid", + "volcanic tremor", + "tremor pulse", + "volcano-tectonic", + "volcanic rockfall", + "lahar", + "pyroclastic flow", + "volcanic eruption"} { + + input := "2024p344188_0.13.xml" + b, err := os.ReadFile("etc/" + input) + if err != nil { + t.Fatal(err) + } + b = bytes.Replace(b, []byte("other"), []byte(fmt.Sprintf("%s", eventType)), -1) + var e event + + if err = unmarshal(b, &e); err != nil { + t.Error(err) + } + if !strings.HasPrefix(e.Quakeml12Event, ``) { + t.Errorf("%s: quakeml fragment should start with `) { + t.Errorf("%s: quakeml fragment should end with ", input) + } + + c := event{ + PublicID: "2024p344188", + EventType: eventType, + Longitude: 176.2128674424493, + Latitude: -38.62063477317881, + Depth: 5.1162109375, + EvaluationMethod: "NonLinLoc", + EarthModel: "nz3drx", + EvaluationMode: "automatic", + EvaluationStatus: "", + UsedPhaseCount: 10, + UsedStationCount: 10, + OriginError: 0.13178423630674604, + AzimuthalGap: 76.05025526639076, + MinimumDistance: 0.0752301603770797, + Magnitude: 1.4089917745797527, + MagnitudeUncertainty: 0, + MagnitudeType: "M", + MagnitudeStationCount: 5, + Deleted: false, + Sc3ml: string(b), + } + + c.ModificationTime, _ = time.Parse(time.RFC3339Nano, "2024-05-07T22:58:22.37962Z") + c.OriginTime, _ = time.Parse(time.RFC3339Nano, "2024-05-07T08:24:09.853066Z") + + if c.Quakeml12Event, err = toQuakeMLEvent(b); err != nil { + t.Error(err) + } + + if !reflect.DeepEqual(e, c) { + t.Errorf("c not equal to e, expected: %+v", e) + } + } +} + // TestEventType tests that the remapping of SC3ML event type to QuakeML is correct. // The bug in the sc3ml_*_quakeml_1.2.xsl conversion (inserting "other" instead of "other event" // has been fixed locally and reported upstream. GMC 12 Sept 2017 diff --git a/cmd/fdsn-ws/fdsn_event_test.go b/cmd/fdsn-ws/fdsn_event_test.go index 8fb1310..6a7b6b1 100644 --- a/cmd/fdsn-ws/fdsn_event_test.go +++ b/cmd/fdsn-ws/fdsn_event_test.go @@ -349,7 +349,7 @@ func TestLongitudeWrap180(t *testing.T) { setup(t) defer teardown() - // test data: one at 176.3257242 and another at -176.3257242 + // test data at: 176.3257242, -176.3257242, 179.3257242 v := url.Values{} v.Set("minlon", "177.0") e, err := parseEventV1(v) @@ -362,8 +362,8 @@ func TestLongitudeWrap180(t *testing.T) { t.Error(err) } - if c != 1 { - t.Errorf("expected 1 records got %d\n", c) + if c != 2 { + t.Errorf("expected 2 records got %d\n", c) } v = url.Values{} @@ -379,8 +379,8 @@ func TestLongitudeWrap180(t *testing.T) { t.Error(err) } - if c != 2 { - t.Errorf("expected 2 records got %d\n", c) + if c != 3 { + t.Errorf("expected 3 records got %d\n", c) } v = url.Values{} @@ -395,8 +395,8 @@ func TestLongitudeWrap180(t *testing.T) { t.Error(err) } - if c != 1 { - t.Errorf("expected 1 records got %d\n", c) + if c != 2 { + t.Errorf("expected 2 records got %d\n", c) } v = url.Values{} @@ -432,6 +432,17 @@ func TestEventTypes(t *testing.T) { {"experimental explosion", false, []interface{}{"experimental explosion"}}, {"e*,a*", false, []interface{}{"earthquake", "explosion", "anthropogenic event", "accidental explosion", "experimental explosion", "atmospheric event", "acoustic noise", "avalanche", "artillery strike", "atmospheric meteor explosion"}}, {"unknown", false, []interface{}{""}}, // specify "unknown" means query for empty value + //new event types + {"volcanic long-period", false, []interface{}{"volcanic long-period"}}, + {"volcanic very-long-period", false, []interface{}{"volcanic very-long-period"}}, + {"volcanic hybrid", false, []interface{}{"volcanic hybrid"}}, + {"volcanic tremor", false, []interface{}{"volcanic tremor"}}, + {"tremor pulse", false, []interface{}{"tremor pulse"}}, + {"volcano-tectonic", false, []interface{}{"volcano-tectonic"}}, + {"volcanic rockfall", false, []interface{}{"volcanic rockfall"}}, + {"pyroclastic flow", false, []interface{}{"pyroclastic flow"}}, + {"volcanic eruption", false, []interface{}{"volcanic eruption"}}, + {"lahar", false, []interface{}{"lahar"}}, } for _, c := range queryCases { v := url.Values{} diff --git a/cmd/fdsn-ws/routes_test.go b/cmd/fdsn-ws/routes_test.go index 98d68d8..49b6603 100644 --- a/cmd/fdsn-ws/routes_test.go +++ b/cmd/fdsn-ws/routes_test.go @@ -22,6 +22,10 @@ var routes = wt.Requests{ {ID: wt.L(), URL: "/fdsnws/event/1/catalogs", Content: "application/xml"}, {ID: wt.L(), URL: "/fdsnws/event/1/contributors", Content: "application/xml"}, {ID: wt.L(), URL: "/fdsnws/event/1/application.wadl", Content: "application/xml"}, + //event type + {ID: wt.L(), URL: "/fdsnws/event/1/query?starttime=2015-01-01T00:00:00&endtime=2015-12-28T22:00:00&format=text&eventtype=volcanic%20long-period", Content: "text/plain"}, + {ID: wt.L(), URL: "/fdsnws/event/1/query?starttime=2015-01-01T00:00:00&endtime=2015-12-28T22:00:00&format=text&eventtype=volcanic%20very-long-period", Content: "text/plain"}, + {ID: wt.L(), URL: "/fdsnws/event/1/query?starttime=2015-01-01T00:00:00&endtime=2015-12-28T22:00:00&format=text&eventtype=other%20event", Content: "text/plain"}, // fdsn-ws-dataselect {ID: wt.L(), URL: "/fdsnws/dataselect/1", Content: "text/html"}, diff --git a/cmd/fdsn-ws/server_test.go b/cmd/fdsn-ws/server_test.go index c282a30..e412fa6 100644 --- a/cmd/fdsn-ws/server_test.go +++ b/cmd/fdsn-ws/server_test.go @@ -40,7 +40,7 @@ func setup(t *testing.T) { t.Fatal("ERROR: problem pinging DB") } - _, err = db.Exec(`DELETE FROM fdsn.event WHERE publicid = '2015p768477' or publicid = '2015p768478'`) + _, err = db.Exec(`DELETE FROM fdsn.event WHERE publicid = '2015p768477' or publicid = '2015p768478' or publicid = '2015p768479'`) if err != nil { t.Log(err) } @@ -51,7 +51,7 @@ func setup(t *testing.T) { usedphasecount, usedstationcount, originerror, azimuthalgap, minimumdistance, magnitudeuncertainty, magnitudestationcount, quakeml12event, sc3ml) VALUES ('2015p768477', timestamptz '2015-10-12 08:05:01.717692+00', timestamptz '2015-10-12 08:05:01.717692+00', - -40.57806609, 176.3257242, 23.28125, 2.3, 'magnitudetype', false, 'eventtype', + -40.57806609, 176.3257242, 23.28125, 2.3, 'magnitudetype', false, 'volcanic long-period', 'depthtype', 'evaluationmethod', 'earthmodel', 'evaluationmode', 'evaluationstatus', 0, 0, 0, 0, 0, 0, 0, 'quakeml12event', 'sc3ml')`) @@ -65,7 +65,7 @@ func setup(t *testing.T) { usedphasecount, usedstationcount, originerror, azimuthalgap, minimumdistance, magnitudeuncertainty, magnitudestationcount, quakeml12event, sc3ml) VALUES ('2015p768478', timestamptz '2015-10-12 08:05:02.717692+00', timestamptz '2015-10-12 08:05:02.717692+00', - -40.57806609, -176.3257242, 23.28125, 2.3, 'magnitudetype', false, 'eventtype', + -40.57806609, -176.3257242, 23.28125, 2.3, 'magnitudetype', false, 'volcanic very-long-period', 'depthtype', 'evaluationmethod', 'earthmodel', 'evaluationmode', 'evaluationstatus', 0, 0, 0, 0, 0, 0, 0, 'quakeml12event', 'sc3ml')`) @@ -73,6 +73,20 @@ func setup(t *testing.T) { t.Log(err) } + _, err = db.Exec(`INSERT INTO fdsn.event (publicid, modificationtime, origintime, + latitude, longitude, depth, magnitude, magnitudetype, deleted, eventtype, + depthtype, evaluationmethod, earthmodel, evaluationmode, evaluationstatus, + usedphasecount, usedstationcount, originerror, azimuthalgap, minimumdistance, + magnitudeuncertainty, magnitudestationcount, quakeml12event, sc3ml) + VALUES ('2015p768479', timestamptz '2015-10-12 09:05:02.717692+00', timestamptz '2015-10-12 09:05:02.717692+00', + -23.57806609, 179.3257242, 33.28125, 2.3, 'magnitudetype', false, 'other event', + 'depthtype', 'evaluationmethod', 'earthmodel', 'evaluationmode', 'evaluationstatus', + 0, 0, 0, 0, 0, + 0, 0, 'quakeml12event', 'sc3ml')`) + if err != nil { + t.Log(err) + } + ts = httptest.NewServer(mux) // Silence the logging unless running with diff --git a/internal/fdsn/dataselect.go b/internal/fdsn/dataselect.go index c42294a..229d614 100644 --- a/internal/fdsn/dataselect.go +++ b/internal/fdsn/dataselect.go @@ -33,9 +33,9 @@ var dataSelectNotSupported = map[string]bool{ "minuimumlength": true, } -// nslcReg: FDSN spec allows all ascii, but we'll only allow alpha, number, _, ?, *, "," and "--" (exactly 2 hyphens only) -var nslcReg = regexp.MustCompile(`^([\w*?,]+|--)$`) -var eventTypeReg = regexp.MustCompile(`^([\w*?, ]+|--)$`) // space allowed +// nslcReg: FDSN spec allows all ascii, but we'll only allow alpha, number, _,-, ?, *, "," and "--" (exactly 2 hyphens only) +var nslcReg = regexp.MustCompile(`^([\w*?,]+(?:-[\w*?,]+)*|--)$`) // space not allowed +var eventTypeReg = regexp.MustCompile(`^([\w*?, ]+(?:[ -][\w*?,]+)*|--)$`) // space allowed // nslcRegPassPattern: This is beyond FDSN spec. // Any NSLC regex string doesn't match this pattern we knew it won't generate any results. @@ -306,6 +306,7 @@ func GenRegex(input []string, emptyDash bool, allowSpace bool) ([]string, error) } else { matched = nslcReg.MatchString(s) } + if !matched { return nil, fmt.Errorf("invalid parameter:'%s'", s) }